Skip to content

Conversation

@Dnouv
Copy link
Member

@Dnouv Dnouv commented Nov 18, 2025

Proposed changes (including videos or screenshots)

Graduate the getUserRoomIds accessor from the experimental bridge into the stable user bridge so apps can rely on a non-experimental API, guarded by the existing user.read permission. The experimental rollout proved stable in testing, so we want to remove the experimental flag, expose the method through the standard accessor, and make the implementation authoritative without the metrics wrapper.

  • Added getUserRoomIds to IUserRead/UserRead and routed it through the user bridge with the regular read permission.
  • Removed the experimental bridge method/permission, cleaned up the accessor stubs/tests, and updated the bridge to provide the implementation directly.

Issue(s)

Steps to test or reproduce

 const appUser = await read.getUserReader().getAppUser();
  if (!appUser?.id) {
          this.getLogger().warn('No app user yet, skipping getUserRoomIds');
          return;
  }

  const roomIds = await read.getUserReader().getUserRoomIds(appUser.id); // [ "GENERAL", "676141ce9225eb5ac77cd169" ]

Further comments

RCAI6-45

Summary by CodeRabbit

  • New Features

    • getUserRoomIds graduated from experimental to stable; apps with read permission can retrieve a user’s associated room IDs.
  • Chores

    • Bumped minor versions for apps engine and platform runtime.
    • Consolidated experimental permission naming into a default experimental entry.
  • Localization

    • Added English label for the experimental permission.
  • Tests

    • Updated tests and fixtures to cover the stable accessor.

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

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Nov 18, 2025

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

@changeset-bot
Copy link

changeset-bot bot commented Nov 18, 2025

🦋 Changeset detected

Latest commit: da87b79

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

This PR includes changesets to release 42 packages
Name Type
@rocket.chat/apps-engine Minor
@rocket.chat/meteor Minor
@rocket.chat/apps Patch
@rocket.chat/core-services Patch
@rocket.chat/core-typings Minor
@rocket.chat/fuselage-ui-kit Major
@rocket.chat/rest-typings Minor
@rocket.chat/ddp-streamer Patch
@rocket.chat/presence Patch
rocketchat-services Patch
@rocket.chat/uikit-playground Patch
@rocket.chat/api-client Patch
@rocket.chat/cron Patch
@rocket.chat/ddp-client Patch
@rocket.chat/freeswitch Patch
@rocket.chat/gazzodown Major
@rocket.chat/http-router Patch
@rocket.chat/livechat Patch
@rocket.chat/model-typings Patch
@rocket.chat/ui-avatar Major
@rocket.chat/ui-client Major
@rocket.chat/ui-contexts Major
@rocket.chat/web-ui-registration Major
@rocket.chat/account-service Patch
@rocket.chat/authorization-service Patch
@rocket.chat/omnichannel-transcript Patch
@rocket.chat/presence-service Patch
@rocket.chat/queue-worker Patch
@rocket.chat/stream-hub-service Patch
@rocket.chat/federation-matrix Patch
@rocket.chat/license Patch
@rocket.chat/media-calls Patch
@rocket.chat/omnichannel-services Patch
@rocket.chat/pdf-worker 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 Major
@rocket.chat/ui-voip Major
@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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 18, 2025

Walkthrough

The PR graduates getUserRoomIds from the experimental API into the stable user bridge: it removes the experimental implementation and permission, adds the method to IUserRead/UserBridge/UserRead, updates Meteor bridge implementations, tests, i18n, and a changeset. (≤50 words)

Changes

Cohort / File(s) Summary
Versioning & Changeset
\.changeset/calm-falcons-gather.md
Bump minor versions and document graduation of getUserRoomIds from experimental to stable.
Meteor bridges
apps/meteor/app/apps/server/bridges/experimental.ts, apps/meteor/app/apps/server/bridges/users.ts
Removed getUserRoomIds and supporting imports/metrics from experimental bridge; added getUserRoomIds implementation to Meteor user bridge (subscription lookup).
APIs — definitions
packages/apps-engine/src/definition/accessors/IExperimentalRead.ts, packages/apps-engine/src/definition/accessors/IUserRead.ts
Removed getUserRoomIds from IExperimentalRead; added non-optional getUserRoomIds(userId: string): Promise<string[]> to IUserRead.
APIs — accessors
packages/apps-engine/src/server/accessors/ExperimentalRead.ts, packages/apps-engine/src/server/accessors/UserRead.ts
Made constructor fields protected/readonly in ExperimentalRead and removed its getUserRoomIds; added public getUserRoomIds in UserRead delegating to bridge.
Bridges — apps-engine
packages/apps-engine/src/server/bridges/ExperimentalBridge.ts, packages/apps-engine/src/server/bridges/UserBridge.ts
ExperimentalBridge stripped of experimental methods; UserBridge gains doGetUserRoomIds(userId, appId) (permission-gated) and an abstract getUserRoomIds(userId, appId) contract.
Permissions
packages/apps-engine/src/server/permissions/AppPermissions.ts
Replaced experimental.getUserRoomIds permission entry with experimental.default.
Tests & test data
packages/apps-engine/tests/server/accessors/UserRead.spec.ts, packages/apps-engine/tests/test-data/bridges/experimentalBridge.ts, packages/apps-engine/tests/test-data/bridges/userBridge.ts
Added test scaffolding and mock doGetUserRoomIds to user bridge tests; removed stubbed experimental implementation; added placeholder in user bridge test data.
i18n
packages/i18n/src/locales/en.i18n.json
Added Apps_Permissions_experimental_default translation key.

Sequence Diagram(s)

sequenceDiagram
    participant App as App
    participant UserRead as UserRead (Accessor)
    participant UserBridge as UserBridge
    participant DB as Database

    App->>UserRead: getUserRoomIds(userId)
    activate UserRead
    UserRead->>UserBridge: doGetUserRoomIds(userId, appId)
    activate UserBridge
    Note right of UserBridge `#e6f7ff`: permission check (hasReadPermission)
    alt has read permission
        UserBridge->>UserBridge: getUserRoomIds(userId, appId)
        UserBridge->>DB: query Subscriptions by userId (project rid)
        DB-->>UserBridge: list of rids
        UserBridge-->>UserRead: Promise<string[]>
    else no permission
        UserBridge-->>UserRead: undefined
    end
    deactivate UserBridge
    deactivate UserRead
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review permission gating in packages/apps-engine/src/server/bridges/UserBridge.ts.
  • Verify constructor visibility changes (private → protected readonly) in ExperimentalRead/bridges.
  • Confirm Meteor users.ts subscription projection and return shape match engine interface and tests.

Possibly related PRs

Suggested reviewers

  • ggazzo
  • lucas-a-pelegrino

Poem

🐇 I hopped through code with nimble paws,
I moved a method, changed the laws.
From experimental burrow to stable gate,
Room IDs hop home, tests celebrate.
Hooray for clean bridges — time to bait the carrot! 🥕

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: promoting getUserRoomIds from experimental to the stable user bridge, which is the primary objective of this PR.
Linked Issues check ✅ Passed The PR fully implements all coding objectives from RCAI6-45: method promoted to user bridge, integrated into IUserRead/UserRead, protected by user.read permission, experimental flag removed, and tests verify no server side effects.
Out of Scope Changes check ✅ Passed All changes are directly related to graduating getUserRoomIds to the user bridge: interface updates, method migrations, permission restructuring, test updates, and i18n entries for the new permission. No unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch new/ae/graduate_uroomid

📜 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 45a749e and 17a00bc.

📒 Files selected for processing (1)
  • packages/i18n/src/locales/en.i18n.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/i18n/src/locales/en.i18n.json
⏰ 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

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.

@Dnouv Dnouv added this to the 7.13.0 milestone Nov 18, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Nov 18, 2025

📦 Docker Image Size Report

📈 Changes

Service Current Baseline Change Percent
sum of all images 1.2GiB 1.2GiB +12MiB
rocketchat 367MiB 355MiB +12MiB
omnichannel-transcript-service 141MiB 141MiB -15B
queue-worker-service 141MiB 141MiB +203B
ddp-streamer-service 127MiB 127MiB +92B
account-service 114MiB 114MiB +1.3KiB
stream-hub-service 111MiB 111MiB +468B
authorization-service 111MiB 111MiB +217B
presence-service 111MiB 111MiB +5B

📊 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 21:05", "11/19 21:39 (PR)"]
  y-axis "Size (GB)" 0 --> 0.5
  line "account-service" [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]
  line "ddp-streamer-service" [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.14]
  line "presence-service" [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.14]
  line "rocketchat" [0.36, 0.36, 0.35, 0.35, 0.35, 0.36]
  line "stream-hub-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
Loading

Statistics (last 5 days):

  • 📊 Average: 1.4GiB
  • ⬇️ 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-37547
  • Baseline: develop
  • Timestamp: 2025-11-19 21:39:57 UTC
  • Historical data points: 5

Updated: Wed, 19 Nov 2025 21:39:58 GMT

@Dnouv Dnouv marked this pull request as ready for review November 19, 2025 06:09
@Dnouv Dnouv requested a review from a team as a code owner November 19, 2025 06:09
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: 2

🧹 Nitpick comments (3)
packages/apps-engine/src/definition/accessors/IExperimentalRead.ts (1)

8-9: Consider removing the empty interface or converting to a type alias.

The IExperimentalRead interface is now empty after the getUserRoomIds migration. If this interface serves no purpose, consider removing it entirely in a future major version. Alternatively, if it must be retained for backward compatibility, follow the static analysis suggestion to convert it to a type alias: export type IExperimentalRead = {}.

packages/apps-engine/src/server/accessors/ExperimentalRead.ts (1)

6-7: Constructor visibility changed to protected.

The constructor parameters have been changed from private to protected readonly, allowing subclasses to access these fields. While this expands the subclass API surface slightly, it's a safe change that may support future extensibility.

apps/meteor/app/apps/server/bridges/experimental.ts (1)

5-5: Constructor visibility changed to protected.

Similar to ExperimentalRead, the constructor parameter has been changed from private readonly to protected readonly. This is a consistent pattern across the experimental bridge implementations and allows for future extensibility.

📜 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 8a6cae6 and bd241fe.

📒 Files selected for processing (13)
  • .changeset/calm-falcons-gather.md (1 hunks)
  • apps/meteor/app/apps/server/bridges/experimental.ts (1 hunks)
  • apps/meteor/app/apps/server/bridges/users.ts (1 hunks)
  • packages/apps-engine/src/definition/accessors/IExperimentalRead.ts (1 hunks)
  • packages/apps-engine/src/definition/accessors/IUserRead.ts (1 hunks)
  • packages/apps-engine/src/server/accessors/ExperimentalRead.ts (1 hunks)
  • packages/apps-engine/src/server/accessors/UserRead.ts (1 hunks)
  • packages/apps-engine/src/server/bridges/ExperimentalBridge.ts (1 hunks)
  • packages/apps-engine/src/server/bridges/UserBridge.ts (2 hunks)
  • packages/apps-engine/src/server/permissions/AppPermissions.ts (0 hunks)
  • packages/apps-engine/tests/server/accessors/UserRead.spec.ts (3 hunks)
  • packages/apps-engine/tests/test-data/bridges/experimentalBridge.ts (1 hunks)
  • packages/apps-engine/tests/test-data/bridges/userBridge.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/apps-engine/src/server/permissions/AppPermissions.ts
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
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).
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.
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.
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.
📚 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:

  • packages/apps-engine/src/definition/accessors/IUserRead.ts
  • apps/meteor/app/apps/server/bridges/users.ts
  • packages/apps-engine/tests/test-data/bridges/experimentalBridge.ts
  • packages/apps-engine/tests/test-data/bridges/userBridge.ts
  • packages/apps-engine/src/server/accessors/ExperimentalRead.ts
  • packages/apps-engine/tests/server/accessors/UserRead.spec.ts
  • packages/apps-engine/src/server/accessors/UserRead.ts
  • .changeset/calm-falcons-gather.md
  • apps/meteor/app/apps/server/bridges/experimental.ts
  • packages/apps-engine/src/server/bridges/UserBridge.ts
  • packages/apps-engine/src/server/bridges/ExperimentalBridge.ts
  • packages/apps-engine/src/definition/accessors/IExperimentalRead.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:

  • packages/apps-engine/src/definition/accessors/IUserRead.ts
  • apps/meteor/app/apps/server/bridges/users.ts
  • packages/apps-engine/tests/test-data/bridges/experimentalBridge.ts
  • packages/apps-engine/tests/test-data/bridges/userBridge.ts
  • packages/apps-engine/src/server/accessors/ExperimentalRead.ts
  • packages/apps-engine/tests/server/accessors/UserRead.spec.ts
  • packages/apps-engine/src/server/accessors/UserRead.ts
  • .changeset/calm-falcons-gather.md
  • apps/meteor/app/apps/server/bridges/experimental.ts
  • packages/apps-engine/src/server/bridges/UserBridge.ts
  • packages/apps-engine/src/server/bridges/ExperimentalBridge.ts
  • packages/apps-engine/src/definition/accessors/IExperimentalRead.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:

  • packages/apps-engine/src/definition/accessors/IUserRead.ts
  • apps/meteor/app/apps/server/bridges/users.ts
  • packages/apps-engine/tests/test-data/bridges/experimentalBridge.ts
  • packages/apps-engine/tests/test-data/bridges/userBridge.ts
  • packages/apps-engine/src/server/accessors/ExperimentalRead.ts
  • packages/apps-engine/tests/server/accessors/UserRead.spec.ts
  • packages/apps-engine/src/server/accessors/UserRead.ts
  • .changeset/calm-falcons-gather.md
  • apps/meteor/app/apps/server/bridges/experimental.ts
  • packages/apps-engine/src/server/bridges/UserBridge.ts
  • packages/apps-engine/src/server/bridges/ExperimentalBridge.ts
  • packages/apps-engine/src/definition/accessors/IExperimentalRead.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:

  • packages/apps-engine/src/definition/accessors/IUserRead.ts
  • apps/meteor/app/apps/server/bridges/users.ts
  • packages/apps-engine/tests/test-data/bridges/userBridge.ts
  • packages/apps-engine/tests/server/accessors/UserRead.spec.ts
  • packages/apps-engine/src/server/accessors/UserRead.ts
  • .changeset/calm-falcons-gather.md
  • apps/meteor/app/apps/server/bridges/experimental.ts
  • packages/apps-engine/src/server/bridges/UserBridge.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:

  • apps/meteor/app/apps/server/bridges/users.ts
  • .changeset/calm-falcons-gather.md
📚 Learning: 2025-10-06T20:30:45.540Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37152
File: packages/apps-engine/tests/test-data/storage/storage.ts:101-122
Timestamp: 2025-10-06T20:30:45.540Z
Learning: In `packages/apps-engine/tests/test-data/storage/storage.ts`, the stub methods (updatePartialAndReturnDocument, updateStatus, updateSetting, updateAppInfo, updateMarketplaceInfo) intentionally throw "Method not implemented." Tests using these methods must stub them using `SpyOn` from the test library rather than relying on actual implementations.

Applied to files:

  • packages/apps-engine/tests/test-data/bridges/experimentalBridge.ts
  • packages/apps-engine/tests/test-data/bridges/userBridge.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:

  • .changeset/calm-falcons-gather.md
  • apps/meteor/app/apps/server/bridges/experimental.ts
📚 Learning: 2025-09-15T06:21:00.139Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 36868
File: apps/meteor/app/apps/server/bridges/serverEndpoints.ts:35-48
Timestamp: 2025-09-15T06:21:00.139Z
Learning: In ServerEndpointsBridge.ts, the permission model distinguishes between token pass-through and true impersonation: `server-endpoints.call` is required for all endpoint access, while `server-endpoints.impersonate` is only required when `info.user.id` is provided without `info.user.token` (lines 48-53), meaning the bridge needs to mint a token. When both user ID and token are provided, it's considered legitimate credential usage, not impersonation.

Applied to files:

  • packages/apps-engine/src/server/bridges/UserBridge.ts
  • packages/apps-engine/src/server/bridges/ExperimentalBridge.ts
🧬 Code graph analysis (2)
packages/apps-engine/tests/test-data/bridges/experimentalBridge.ts (1)
packages/apps-engine/src/server/bridges/index.ts (1)
  • ExperimentalBridge (49-49)
packages/apps-engine/src/server/bridges/ExperimentalBridge.ts (1)
packages/apps-engine/src/server/bridges/index.ts (1)
  • ExperimentalBridge (49-49)
🪛 Biome (2.1.2)
packages/apps-engine/src/definition/accessors/IExperimentalRead.ts

[error] 9-9: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

🔇 Additional comments (11)
.changeset/calm-falcons-gather.md (1)

1-6: LGTM! Clear documentation of the API graduation.

The changeset appropriately documents the graduation of getUserRoomIds from experimental to stable with correct minor version bumps for both affected packages.

packages/apps-engine/src/definition/accessors/IUserRead.ts (1)

23-28: LGTM! Clean interface addition with proper documentation.

The getUserRoomIds method is correctly added to the IUserRead interface with appropriate JSDoc and a return type that accounts for permission-denied scenarios.

packages/apps-engine/src/server/accessors/UserRead.ts (1)

27-29: LGTM! Consistent delegation pattern.

The implementation follows the established pattern of delegating to the bridge layer, maintaining consistency with other methods in the UserRead class.

packages/apps-engine/tests/test-data/bridges/userBridge.ts (1)

41-43: LGTM! Consistent test scaffolding.

The stub method follows the established pattern for test bridges, where methods throw "Method not implemented." and are stubbed using SpyOn in actual tests.

packages/apps-engine/tests/test-data/bridges/experimentalBridge.ts (1)

3-3: LGTM! Correct removal of experimental method override.

The removal of the getUserRoomIds override aligns with the broader migration away from the experimental bridge, simplifying the test bridge to rely solely on the base ExperimentalBridge implementation.

packages/apps-engine/src/server/bridges/UserBridge.ts (1)

76-76: Clarify intent: does the abstract method signature represent the implementation contract or the wrapper contract?

The abstract method signature declares Promise<string[] | undefined>, but the concrete implementation AppUserBridge.getUserRoomIds (apps/meteor/app/apps/server/bridges/users.ts:172-178) always returns a string[] array—never undefined. The undefined return actually comes from the public wrapper doGetUserRoomIds (line 48-52), which implicitly returns undefined when permission checks fail.

Two possible directions:

  1. Narrow the abstract signature to Promise<string[]> if implementations should never return undefined (wrapper handles permission denial)
  2. Keep the current signature if subclasses are intended to return undefined in error cases or other scenarios beyond the current implementation
packages/apps-engine/src/server/bridges/ExperimentalBridge.ts (1)

10-10: LGTM! Clean graduation of experimental feature.

The getUserRoomIds method has been successfully removed from the experimental bridge, leaving a clean placeholder for future experimental features.

packages/apps-engine/tests/server/accessors/UserRead.spec.ts (3)

15-15: LGTM! Proper test fixture setup.

The roomIds fixture is correctly initialized with test data for the graduated getUserRoomIds functionality.

Also applies to: 20-20


33-35: LGTM! Mock implementation added for graduated method.

The doGetUserRoomIds mock properly returns the test fixture data, enabling verification of the graduated API.


54-54: LGTM! Test coverage added for getUserRoomIds.

The test properly verifies that getUserRoomIds returns the expected room IDs through the UserRead accessor.

apps/meteor/app/apps/server/bridges/experimental.ts (1)

1-8: Fix missing explicit return statement in UserBridge.doGetUserRoomIds permission-denied case.

The bug from previous learnings persists in the stable implementation. In packages/apps-engine/src/server/bridges/UserBridge.ts, the doGetUserRoomIds method (lines showing permission check only) implicitly returns undefined when hasReadPermission(appId) is false—there's no explicit return or else clause. Add an explicit return undefined; or return []; in the else case to make the permission-denied behavior clear.

⛔ Skipped due to learnings
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).
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.
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.
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 36868
File: apps/meteor/app/apps/server/bridges/serverEndpoints.ts:35-48
Timestamp: 2025-09-15T06:21:00.139Z
Learning: In ServerEndpointsBridge.ts, the impersonation permission (`server-endpoints.impersonate`) is enforced at lines 48-49 specifically when `info.user` is provided without `info.user.token`, which represents the impersonation scenario where a token needs to be minted. Token pass-through (when both user ID and token are provided) doesn't require the impersonate permission since the app already possesses a valid token.

Copy link
Member

@d-gubert d-gubert left a comment

Choose a reason for hiding this comment

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

Almost there! Just have a couple of things to iron out. Make sure to address the Code Rabbit comment as well

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

📜 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 7441191 and 45a749e.

📒 Files selected for processing (7)
  • apps/meteor/app/apps/server/bridges/users.ts (1 hunks)
  • packages/apps-engine/src/definition/accessors/IUserRead.ts (1 hunks)
  • packages/apps-engine/src/server/accessors/UserRead.ts (1 hunks)
  • packages/apps-engine/src/server/bridges/UserBridge.ts (2 hunks)
  • packages/apps-engine/src/server/permissions/AppPermissions.ts (1 hunks)
  • packages/apps-engine/tests/test-data/bridges/userBridge.ts (1 hunks)
  • packages/i18n/src/locales/en.i18n.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/apps-engine/src/server/accessors/UserRead.ts
  • packages/apps-engine/tests/test-data/bridges/userBridge.ts
  • packages/apps-engine/src/server/bridges/UserBridge.ts
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
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).
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.
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.
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.
📚 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:

  • packages/apps-engine/src/server/permissions/AppPermissions.ts
  • packages/apps-engine/src/definition/accessors/IUserRead.ts
  • apps/meteor/app/apps/server/bridges/users.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:

  • packages/apps-engine/src/definition/accessors/IUserRead.ts
  • apps/meteor/app/apps/server/bridges/users.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:

  • packages/apps-engine/src/definition/accessors/IUserRead.ts
  • apps/meteor/app/apps/server/bridges/users.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:

  • packages/apps-engine/src/definition/accessors/IUserRead.ts
  • apps/meteor/app/apps/server/bridges/users.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/app/apps/server/bridges/users.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
🔇 Additional comments (3)
packages/apps-engine/src/definition/accessors/IUserRead.ts (1)

23-28: LGTM! Interface definition is consistent with implementation.

The return type Promise<string[]> correctly reflects that this method always returns an array (empty when the user has no subscriptions), which is consistent with the implementation in apps/meteor/app/apps/server/bridges/users.ts.

Based on learnings

apps/meteor/app/apps/server/bridges/users.ts (1)

172-178: LGTM! Implementation is correct and return type consistency issue resolved.

The implementation correctly:

  • Queries subscriptions with minimal projection for efficiency
  • Returns an array of room IDs (empty array when user has no subscriptions)
  • Uses the non-optional return type Promise<string[]>, which is now consistent with the interface definition in IUserRead.ts (line 28)

The return type mismatch flagged in previous reviews has been addressed.

Based on learnings

packages/apps-engine/src/server/permissions/AppPermissions.ts (1)

125-127: Good consolidation following past feedback.

The change from a specific getUserRoomIds permission to a generic experimental.default permission aligns with d-gubert's previous suggestion to keep the experimental scope for future APIs. This approach allows the experimental permission to be reused as new experimental features are added. The corresponding i18n key Apps_Permissions_experimental_default is confirmed present in the locale files.

@d-gubert d-gubert changed the title feat: Graduate getUserRoomIds to the user bridge feat(apps): graduate getUserRoomIds experiment to the user bridge Nov 19, 2025
@codecov
Copy link

codecov bot commented Nov 19, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.95%. Comparing base (035e0c7) to head (da87b79).
⚠️ Report is 2 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #37547      +/-   ##
===========================================
- Coverage    68.97%   68.95%   -0.02%     
===========================================
  Files         3359     3359              
  Lines       114214   114177      -37     
  Branches     20535    20533       -2     
===========================================
- Hits         78784    78736      -48     
- Misses       33335    33351      +16     
+ Partials      2095     2090       -5     
Flag Coverage Δ
e2e 57.39% <ø> (-0.06%) ⬇️
e2e-api 42.83% <ø> (-0.02%) ⬇️

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.

@d-gubert d-gubert added the stat: QA assured Means it has been tested and approved by a company insider label Nov 19, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Nov 19, 2025
@kodiakhq kodiakhq bot merged commit 5f075ea into develop Nov 19, 2025
69 of 71 checks passed
@kodiakhq kodiakhq bot deleted the new/ae/graduate_uroomid branch November 19, 2025 22:02
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.

3 participants