chore: Convert some apis to openAPI #39265
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 |
|
WalkthroughMigrates many v1 API routes from API.v1.addRoute to explicit HTTP-method registrations (API.v1.get/post/put/delete) with AJV-based request/response schemas, updates core/rest typings and new directory types, enhances router error messages, and adjusts client typings and tests to match new schemas. Changes
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ 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. Comment |
ab8a39c to
d91f357
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #39265 +/- ##
===========================================
+ Coverage 70.90% 70.93% +0.02%
===========================================
Files 3197 3197
Lines 113339 113348 +9
Branches 20544 20525 -19
===========================================
+ Hits 80367 80399 +32
+ Misses 30924 30899 -25
- Partials 2048 2050 +2
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
d91f357 to
3b24978
Compare
e57e31d to
344d5fb
Compare
5f1c345 to
4a7f5fa
Compare
There was a problem hiding this comment.
1 issue found across 32 files
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="apps/meteor/app/api/server/v1/moderation.ts">
<violation number="1" location="apps/meteor/app/api/server/v1/moderation.ts:138">
P1: `moderation.userReports` is wired to the wrong 200-response schema; its payload shape does not match `paginatedReportsResponseSchema`.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (4)
apps/meteor/app/api/server/v1/email-inbox.ts (1)
79-82: Consider simplifying themaxRetriesextraction.Since
isEmailInboxvalidates the body and theEmailInboxPropstype already definesmaxRetries?: numberinimap, the type assertions here are verbose. A simpler approach would leverage the validated type directly.✨ Suggested simplification
- const maxRetries = - 'maxRetries' in body.imap && typeof (body.imap as { maxRetries?: number }).maxRetries === 'number' - ? (body.imap as { maxRetries: number }).maxRetries - : 5; + const maxRetries = body.imap.maxRetries ?? 5;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/app/api/server/v1/email-inbox.ts` around lines 79 - 82, The current verbose extraction of maxRetries can be simplified: since isEmailInbox validates the request and EmailInboxProps declares imap.maxRetries as optional, remove the type assertions and conditional checks and instead read maxRetries directly from body.imap using optional chaining and a fallback (default) of 5; update the assignment for the maxRetries variable (referencing maxRetries and body.imap) to use this simpler pattern and drop the unnecessary casts.apps/meteor/app/api/server/v1/calendar.ts (1)
17-25: Empty schema definition fordataproperty.The
data: {}schema is effectively a no-op validation that allows any value. For proper validation, define the array structure:Suggested schema improvement
const successWithDataSchema = ajv.compile<{ data: ICalendarEvent[] }>({ type: 'object', properties: { - data: {}, + data: { + type: 'array', + items: { $ref: '#/components/schemas/ICalendarEvent' }, + }, success: { type: 'boolean', enum: [true] }, }, required: ['data', 'success'], additionalProperties: false, });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/app/api/server/v1/calendar.ts` around lines 17 - 25, The successWithDataSchema currently uses an empty schema for the data property which allows any value; update the data property in successWithDataSchema to a proper array schema (type: "array") whose items validate ICalendarEvent shape (either inline with items: { type: "object", properties: { ... } , required: [...] } matching ICalendarEvent fields or by referencing a defined schema/$ref for ICalendarEvent), so the compiled schema enforces that data is an array of valid ICalendarEvent objects and still requires success: true and no additionalProperties.apps/meteor/app/api/server/v1/integrations.ts (1)
225-271: Consider adding block scope to switch cases for safer variable declarations.The
const outgoingId(line 241) andconst incomingId(line 262) declarations inside switch cases without block scope could lead to potential variable access issues if the code is modified in the future. While the current logic with early returns prevents this, adding blocks is a defensive pattern.♻️ Optional: Add block scope to switch cases
switch (bodyParams.type) { - case 'webhook-outgoing': + case 'webhook-outgoing': { if (!bodyParams.target_url && !bodyParams.integrationId) { return API.v1.failure('An integrationId or target_url needs to be provided.'); } // ... existing code ... const outgoingId = integration._id; await deleteOutgoingIntegration(outgoingId, this.userId); return API.v1.success({ integration, }); - case 'webhook-incoming': + } + case 'webhook-incoming': { // ... existing code ... const incomingId = integration._id; await deleteIncomingIntegration(incomingId, this.userId); return API.v1.success({ integration, }); + } default: return API.v1.failure('Invalid integration type.'); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/app/api/server/v1/integrations.ts` around lines 225 - 271, The switch cases declare consts outgoingId and incomingId without block braces which risks name collisions if cases are later modified; wrap the 'webhook-outgoing' and 'webhook-incoming' case bodies in their own block scopes (add { ... } around each case body) so the declarations for outgoingId/incomingId and the calls to Integrations.findOne, deleteOutgoingIntegration, and deleteIncomingIntegration are confined to their respective blocks and cannot leak or collide.apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx (1)
120-120: Improve REST type definitions to eliminate the double cast workaround.The double cast
as unknown as Serialized<IDirectoryUserResult>is a workaround for incomplete REST typing. The endpoint correctly supportstype='users'filtering viauseDirectoryQuery(..., 'users', workspace), which ensures only user results are returned. However, the REST type definition returns a union(IDirectoryUserResult | IDirectoryChannelResult)[]regardless of thetypeparameter.Consider updating
/v1/directoryendpoint typing to support type-narrowed return types, so the return type isIDirectoryUserResult[]whentype='users'is passed, eliminating the need for the cast.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx` at line 120, The code uses a double-cast in UsersTable.tsx (user={user as unknown as Serialized<IDirectoryUserResult>}) because the /v1/directory REST types always return a union; fix by updating the directory endpoint typing (e.g., the useDirectoryQuery hook or its underlying API client) to be type-narrowing/overloaded so when called with type='users' it returns Serialized<IDirectoryUserResult[]>, or add a generic type parameter to useDirectoryQuery that infers the return as IDirectoryUserResult[]; after updating the endpoint/useDirectoryQuery signature, remove the double-cast in UsersTable.tsx and use the correct typed user value directly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/meteor/app/api/server/v1/calendar.ts`:
- Around line 88-99: The info action in calendar-events (function action calling
Calendar.get) returns API.v1.failure() when access is denied but the
update/delete handlers throw new Error('invalid-calendar-event'), causing
inconsistent error shapes; choose one approach and make them consistent: either
change the info handler to throw new Error('invalid-calendar-event') when
event?.uid !== userId, or update the update/delete handlers to return
API.v1.failure({ error: 'invalid-calendar-event' })/API.v1.failure() as the
other endpoints do; locate the access check in action(), Calendar.get usage, and
the throw sites ('invalid-calendar-event') to apply the same response pattern
across calendar-events.info, calendar-events.update, and calendar-events.delete.
In `@apps/meteor/app/api/server/v1/email-inbox.ts`:
- Around line 121-137: The 200 response schema currently allows IEmailInbox |
null but the handler returns API.v1.notFound() (404) for missing inboxes so the
null branch is unreachable; update the ajv.compile call that builds the 200
schema to remove the { type: 'null' } branch and the surrounding oneOf so the
response schema only validates IEmailInbox (referencing IEmailInbox in the
schema), and ensure no code paths expect a 200 null—keep API.v1.notFound() for
missing inboxes (adjust any related type annotations if necessary).
In `@apps/meteor/app/api/server/v1/misc.ts`:
- Around line 603-612: The 429 response schema is never used because the broad
catch converts rate-limit Meteor.Error into API.v1.failure(mountResult(...));
update the catch logic to detect the rate-limit error (check for Meteor.Error or
its identifying fields) and, when matched, call API.v1.failure(mountResult(...),
429) or otherwise return the mounted 429 payload instead of the generic failure;
adjust the catch in the same handler that references
methodCallResponseSchema/methodCallErrorResponseSchema so the rate-limit branch
becomes reachable and leave other errors to continue using the existing
API.v1.failure behavior.
- Around line 333-373: The users item schema in spotlightResponseSchema wrongly
marks optional IUser fields as required — remove "name" and "statusText" from
the users.items.required array (keep _id, username, status if those are truly
required) so that a user object missing name or statusText still validates;
reference the spotlightResponseSchema variable and the users/
users.items.required entries when making the change.
In `@apps/meteor/app/api/server/v1/roles.ts`:
- Around line 311-341: The route handler for 'roles.getUsersInPublicRoles' sets
authRequired: true but the response schema only declares 200; add a 401 response
mapping under the same response object to declare the unauthenticated response
shape (e.g., an error object with success: false and an error/message field) so
the route contract covers unauthenticated requests; update the response block
associated with 'roles.getUsersInPublicRoles' to include this 401 AJV schema
alongside the existing 200 schema.
In `@apps/meteor/app/api/server/v1/settings.ts`:
- Around line 137-169: The route response map for API.v1.get('settings.public')
(which uses isSettingsPublicWithPaginationProps and calls parseJsonQuery) is
missing a 400 response entry for malformed sort/fields/query payloads; update
the route's response object to include a 400 entry (using the existing
bad-request/validation error response schema used elsewhere) so validation
failures are part of the contract, and make the same change to the other
settings route that also calls parseJsonQuery (the second settings handler
referenced in the review).
- Around line 209-239: The 400 response schema for the
API.v1.post('settings.addCustomOAuth') route is too strict and doesn't allow
errorType (used by body-validation and the 'error-name-param-not-provided'
Meteor.Error), causing real 400 responses to fail schema validation; update the
400 response schema in this route (near addCustomOAuthBodySchema and the action
that calls addOAuthServiceMethod) to either include an optional errorType
property (e.g., properties: { success, error, errorType }) or allow
additionalProperties so that errorType is accepted, ensuring actual bad-request
responses validate.
In `@docs/api-endpoint-migration.md`:
- Around line 408-409: Update the wording to narrow the claim about module
augmentations so it only asserts visibility for packages that actually consume
the augmentation (e.g., the packages compiled together with the augmentation),
and add a brief note that augmentations declared in apps/meteor (the declare
module '@rocket.chat/rest-typings' augmentation) are not visible to packages
built in isolation (for example packages/ddp-client) because project references
are not used; keep the guidance about chaining endpoints and using
ExtractRoutesFromAPI and augmenting the Endpoints interface but explicitly state
this only makes routes fully typed for consumers that share the same compilation
context, and add an analogous clarification where the same claim appears in
lines 464-489.
---
Nitpick comments:
In `@apps/meteor/app/api/server/v1/calendar.ts`:
- Around line 17-25: The successWithDataSchema currently uses an empty schema
for the data property which allows any value; update the data property in
successWithDataSchema to a proper array schema (type: "array") whose items
validate ICalendarEvent shape (either inline with items: { type: "object",
properties: { ... } , required: [...] } matching ICalendarEvent fields or by
referencing a defined schema/$ref for ICalendarEvent), so the compiled schema
enforces that data is an array of valid ICalendarEvent objects and still
requires success: true and no additionalProperties.
In `@apps/meteor/app/api/server/v1/email-inbox.ts`:
- Around line 79-82: The current verbose extraction of maxRetries can be
simplified: since isEmailInbox validates the request and EmailInboxProps
declares imap.maxRetries as optional, remove the type assertions and conditional
checks and instead read maxRetries directly from body.imap using optional
chaining and a fallback (default) of 5; update the assignment for the maxRetries
variable (referencing maxRetries and body.imap) to use this simpler pattern and
drop the unnecessary casts.
In `@apps/meteor/app/api/server/v1/integrations.ts`:
- Around line 225-271: The switch cases declare consts outgoingId and incomingId
without block braces which risks name collisions if cases are later modified;
wrap the 'webhook-outgoing' and 'webhook-incoming' case bodies in their own
block scopes (add { ... } around each case body) so the declarations for
outgoingId/incomingId and the calls to Integrations.findOne,
deleteOutgoingIntegration, and deleteIncomingIntegration are confined to their
respective blocks and cannot leak or collide.
In `@apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx`:
- Line 120: The code uses a double-cast in UsersTable.tsx (user={user as unknown
as Serialized<IDirectoryUserResult>}) because the /v1/directory REST types
always return a union; fix by updating the directory endpoint typing (e.g., the
useDirectoryQuery hook or its underlying API client) to be
type-narrowing/overloaded so when called with type='users' it returns
Serialized<IDirectoryUserResult[]>, or add a generic type parameter to
useDirectoryQuery that infers the return as IDirectoryUserResult[]; after
updating the endpoint/useDirectoryQuery signature, remove the double-cast in
UsersTable.tsx and use the correct typed user value directly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5615f276-459f-4ca2-9036-cfc5f0632a88
📒 Files selected for processing (32)
apps/meteor/app/api/server/definition.tsapps/meteor/app/api/server/v1/assets.tsapps/meteor/app/api/server/v1/autotranslate.tsapps/meteor/app/api/server/v1/banners.tsapps/meteor/app/api/server/v1/calendar.tsapps/meteor/app/api/server/v1/cloud.tsapps/meteor/app/api/server/v1/e2e.tsapps/meteor/app/api/server/v1/email-inbox.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/integrations.tsapps/meteor/app/api/server/v1/misc.tsapps/meteor/app/api/server/v1/moderation.tsapps/meteor/app/api/server/v1/roles.tsapps/meteor/app/api/server/v1/settings.tsapps/meteor/app/api/server/v1/videoConference.tsapps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsxapps/meteor/client/views/directory/tabs/users/UsersTable/UsersTableRow.tsxapps/meteor/tests/end-to-end/api/banners.tsapps/meteor/tests/end-to-end/api/cloud.tsapps/meteor/tests/end-to-end/api/incoming-integrations.tsapps/meteor/tests/end-to-end/api/livechat/11-email-inbox.tsapps/meteor/tests/end-to-end/api/outgoing-integrations.tsdocs/api-endpoint-migration.mdpackages/core-typings/src/Ajv.tspackages/core-typings/src/IRoom.tspackages/core-typings/src/IUser.tspackages/http-router/src/Router.spec.tspackages/http-router/src/Router.tspackages/models/src/models/ModerationReports.tspackages/rest-typings/src/v1/directory.tspackages/rest-typings/src/v1/email-inbox.tspackages/rest-typings/src/v1/misc.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). (9)
- GitHub Check: cubic · AI code reviewer
- GitHub Check: 🔨 Test UI (EE) / MongoDB 8.0 coverage (4/5)
- GitHub Check: 🔨 Test UI (EE) / MongoDB 8.0 coverage (5/5)
- GitHub Check: 🔨 Test UI (EE) / MongoDB 8.0 coverage (3/5)
- GitHub Check: 🔨 Test UI (EE) / MongoDB 8.0 coverage (2/5)
- GitHub Check: 🔨 Test UI (EE) / MongoDB 8.0 coverage (1/5)
- GitHub Check: 🔨 Test UI (CE) / MongoDB 8.0 (4/4)
- GitHub Check: 🔨 Test UI (CE) / MongoDB 8.0 (2/4)
- GitHub Check: 🔨 Test UI (CE) / MongoDB 8.0 (1/4)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation
Files:
packages/http-router/src/Router.spec.tspackages/rest-typings/src/v1/email-inbox.tspackages/models/src/models/ModerationReports.tspackages/rest-typings/src/v1/misc.tsapps/meteor/app/api/server/definition.tspackages/http-router/src/Router.tspackages/rest-typings/src/v1/directory.tspackages/core-typings/src/IUser.tsapps/meteor/app/api/server/v1/misc.tsapps/meteor/app/api/server/v1/videoConference.tspackages/core-typings/src/IRoom.tsapps/meteor/tests/end-to-end/api/outgoing-integrations.tsapps/meteor/client/views/directory/tabs/users/UsersTable/UsersTableRow.tsxapps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsxapps/meteor/tests/end-to-end/api/incoming-integrations.tsapps/meteor/tests/end-to-end/api/livechat/11-email-inbox.tsapps/meteor/app/api/server/v1/cloud.tsapps/meteor/tests/end-to-end/api/cloud.tsapps/meteor/app/api/server/v1/banners.tsapps/meteor/tests/end-to-end/api/banners.tsapps/meteor/app/api/server/v1/roles.tsapps/meteor/app/api/server/v1/email-inbox.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/assets.tspackages/core-typings/src/Ajv.tsapps/meteor/app/api/server/v1/integrations.tsapps/meteor/app/api/server/v1/calendar.tsapps/meteor/app/api/server/v1/settings.tsapps/meteor/app/api/server/v1/moderation.tsapps/meteor/app/api/server/v1/autotranslate.tsapps/meteor/app/api/server/v1/e2e.ts
**/*.spec.ts
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.spec.ts: Use descriptive test names that clearly communicate expected behavior in Playwright tests
Use.spec.tsextension for test files (e.g.,login.spec.ts)
Files:
packages/http-router/src/Router.spec.ts
🧠 Learnings (41)
📓 Common learnings
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:09.561Z
Learning: In RocketChat/Rocket.Chat OpenAPI migration PRs for apps/meteor/app/api/server/v1 endpoints, maintainers prefer to avoid any logic changes; style-only cleanups (like removing inline comments) may be deferred to follow-ups to keep scope tight.
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:18.785Z
Learning: In Rocket.Chat PR reviews, maintain strict scope boundaries—when a PR is focused on a specific endpoint (e.g., rooms.favorite), avoid reviewing or suggesting changes to other endpoints that were incidentally refactored (e.g., rooms.invite) unless explicitly requested by maintainers.
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 39414
File: apps/meteor/app/api/server/v1/rooms.ts:1241-1297
Timestamp: 2026-03-10T08:13:52.153Z
Learning: In the RocketChat/Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1/rooms.ts, the pattern `ajv.compile<void>({...})` is intentionally used for the 200 response schema even when the endpoint returns `{ success: true }`. This is an established convention across all migrated endpoints (rooms.leave, rooms.favorite, rooms.delete, rooms.muteUser, rooms.unmuteUser). Do not flag this as a type mismatch during reviews of these migration PRs.
📚 Learning: 2025-09-15T13:10:30.049Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 36868
File: packages/http-router/src/Router.ts:416-425
Timestamp: 2025-09-15T13:10:30.049Z
Learning: In packages/http-router/src/Router.ts, the dispatch() method's use of replaceAll('//', '/') on the full path is acceptable because URL normalization and query string handling is performed by the caller function before dispatch() is invoked.
Applied to files:
packages/http-router/src/Router.spec.tspackages/http-router/src/Router.ts
📚 Learning: 2026-01-26T18:26:01.279Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 38227
File: apps/meteor/app/api/server/router.ts:44-49
Timestamp: 2026-01-26T18:26:01.279Z
Learning: In apps/meteor/app/api/server/router.ts, when retrieving bodyParams and queryParams from the Hono context via c.get(), do not add defensive defaults (e.g., ?? {}). The code should fail fast if these parameters are missing, as endpoint handlers expect them to be present and breaking here helps surface parsing problems rather than hiding them.
Applied to files:
packages/http-router/src/Router.spec.tsdocs/api-endpoint-migration.mdapps/meteor/app/api/server/v1/misc.tsapps/meteor/app/api/server/v1/videoConference.tsapps/meteor/tests/end-to-end/api/incoming-integrations.tsapps/meteor/app/api/server/v1/import.ts
📚 Learning: 2025-12-10T21:00:43.645Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37091
File: ee/packages/abac/jest.config.ts:4-7
Timestamp: 2025-12-10T21:00:43.645Z
Learning: Adopt the monorepo-wide Jest testMatch pattern: <rootDir>/src/**/*.spec.{ts,js,mjs} (represented here as '**/src/**/*.spec.{ts,js,mjs}') to ensure spec files under any package's src directory are picked up consistently across all packages in the Rocket.Chat monorepo. Apply this pattern in jest.config.ts for all relevant packages to maintain uniform test discovery.
Applied to files:
packages/http-router/src/Router.spec.ts
📚 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/http-router/src/Router.spec.tsapps/meteor/tests/end-to-end/api/cloud.ts
📚 Learning: 2026-02-24T19:22:48.358Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 38493
File: apps/meteor/tests/e2e/omnichannel/omnichannel-send-pdf-transcript.spec.ts:66-67
Timestamp: 2026-02-24T19:22:48.358Z
Learning: In Playwright end-to-end tests (e.g., under apps/meteor/tests/e2e/...), prefer locating elements by translated text (getByText) and ARIA roles (getByRole) over data-qa attributes. If translation values change, update the corresponding test locators accordingly. Never use data-qa locators. This guideline applies to all Playwright e2e test specs in the repository and helps keep tests robust to UI text changes and accessible semantics.
Applied to files:
packages/http-router/src/Router.spec.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.
Applied to files:
packages/http-router/src/Router.spec.tspackages/rest-typings/src/v1/email-inbox.tspackages/models/src/models/ModerationReports.tspackages/rest-typings/src/v1/misc.tsapps/meteor/app/api/server/definition.tspackages/http-router/src/Router.tspackages/rest-typings/src/v1/directory.tspackages/core-typings/src/IUser.tsapps/meteor/app/api/server/v1/misc.tsapps/meteor/app/api/server/v1/videoConference.tspackages/core-typings/src/IRoom.tsapps/meteor/tests/end-to-end/api/outgoing-integrations.tsapps/meteor/tests/end-to-end/api/incoming-integrations.tsapps/meteor/tests/end-to-end/api/livechat/11-email-inbox.tsapps/meteor/app/api/server/v1/cloud.tsapps/meteor/tests/end-to-end/api/cloud.tsapps/meteor/app/api/server/v1/banners.tsapps/meteor/tests/end-to-end/api/banners.tsapps/meteor/app/api/server/v1/roles.tsapps/meteor/app/api/server/v1/email-inbox.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/assets.tspackages/core-typings/src/Ajv.tsapps/meteor/app/api/server/v1/integrations.tsapps/meteor/app/api/server/v1/calendar.tsapps/meteor/app/api/server/v1/settings.tsapps/meteor/app/api/server/v1/moderation.tsapps/meteor/app/api/server/v1/autotranslate.tsapps/meteor/app/api/server/v1/e2e.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.
Applied to files:
packages/http-router/src/Router.spec.tspackages/rest-typings/src/v1/email-inbox.tspackages/models/src/models/ModerationReports.tspackages/rest-typings/src/v1/misc.tsapps/meteor/app/api/server/definition.tspackages/http-router/src/Router.tspackages/rest-typings/src/v1/directory.tspackages/core-typings/src/IUser.tsapps/meteor/app/api/server/v1/misc.tsapps/meteor/app/api/server/v1/videoConference.tspackages/core-typings/src/IRoom.tsapps/meteor/tests/end-to-end/api/outgoing-integrations.tsapps/meteor/tests/end-to-end/api/incoming-integrations.tsapps/meteor/tests/end-to-end/api/livechat/11-email-inbox.tsapps/meteor/app/api/server/v1/cloud.tsapps/meteor/tests/end-to-end/api/cloud.tsapps/meteor/app/api/server/v1/banners.tsapps/meteor/tests/end-to-end/api/banners.tsapps/meteor/app/api/server/v1/roles.tsapps/meteor/app/api/server/v1/email-inbox.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/assets.tspackages/core-typings/src/Ajv.tsapps/meteor/app/api/server/v1/integrations.tsapps/meteor/app/api/server/v1/calendar.tsapps/meteor/app/api/server/v1/settings.tsapps/meteor/app/api/server/v1/moderation.tsapps/meteor/app/api/server/v1/autotranslate.tsapps/meteor/app/api/server/v1/e2e.ts
📚 Learning: 2026-03-06T18:10:15.268Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39397
File: packages/gazzodown/src/code/CodeBlock.spec.tsx:47-68
Timestamp: 2026-03-06T18:10:15.268Z
Learning: In tests (especially those using testing-library/dom/jsdom) for Rocket.Chat components, the HTML <code> element has an implicit ARIA role of 'code'. Therefore, screen.getByRole('code') or screen.findByRole('code') will locate <code> elements even without a role attribute. Do not flag findByRole('code') as invalid in reviews; prefer using the implicit role instead of adding role="code" unless necessary for accessibility.
Applied to files:
packages/http-router/src/Router.spec.ts
📚 Learning: 2026-03-03T11:11:48.541Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 39230
File: apps/meteor/app/api/server/v1/chat.ts:214-222
Timestamp: 2026-03-03T11:11:48.541Z
Learning: In apps/meteor/server/lib/moderation/reportMessage.ts, the reportMessage function validates that description is not empty or whitespace-only with `if (!description.trim())`. When migrating the chat.reportMessage endpoint to OpenAPI, adding minLength validation to the schema preserves this existing behavior.
Applied to files:
packages/models/src/models/ModerationReports.tsapps/meteor/app/api/server/v1/misc.tsapps/meteor/tests/end-to-end/api/incoming-integrations.tsapps/meteor/tests/end-to-end/api/livechat/11-email-inbox.tsapps/meteor/app/api/server/v1/email-inbox.tsapps/meteor/app/api/server/v1/moderation.tsapps/meteor/app/api/server/v1/autotranslate.ts
📚 Learning: 2026-03-09T18:39:21.178Z
Learnt from: Harxhit
Repo: RocketChat/Rocket.Chat PR: 39476
File: apps/meteor/server/methods/addAllUserToRoom.ts:0-0
Timestamp: 2026-03-09T18:39:21.178Z
Learning: In apps/meteor/server/methods/addAllUserToRoom.ts, the implementation uses a single cursor pass (Users.find(userFilter).batchSize(100)) that collects both the full user objects (collectedUsers: IUser[]) and their usernames (usernames: string[]) in one iteration. `beforeAddUserToRoom` is then called once with the full usernames batch (preserving batch-validation semantics), and the subsequent subscription/message processing loop iterates over the same stable `collectedUsers` array — no second DB query is made. This avoids any race condition between validation and processing while preserving the original batch-validation behavior.
Applied to files:
packages/models/src/models/ModerationReports.tsapps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.
Applied to files:
packages/models/src/models/ModerationReports.tsapps/meteor/app/api/server/v1/misc.tsapps/meteor/tests/end-to-end/api/incoming-integrations.tsapps/meteor/app/api/server/v1/cloud.tsapps/meteor/tests/end-to-end/api/cloud.tsapps/meteor/app/api/server/v1/banners.tsapps/meteor/tests/end-to-end/api/banners.tsapps/meteor/app/api/server/v1/email-inbox.tspackages/core-typings/src/Ajv.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/models/src/models/ModerationReports.tspackages/rest-typings/src/v1/directory.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/models/src/models/ModerationReports.tspackages/rest-typings/src/v1/directory.ts
📚 Learning: 2026-02-25T20:10:16.987Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38913
File: packages/ddp-client/src/legacy/types/SDKLegacy.ts:34-34
Timestamp: 2026-02-25T20:10:16.987Z
Learning: In the RocketChat/Rocket.Chat monorepo, packages/ddp-client and apps/meteor do not use TypeScript project references. Module augmentations in apps/meteor (e.g., declare module 'rocket.chat/rest-typings') are not visible when compiling packages/ddp-client in isolation, which is why legacy SDK methods that depend on OperationResult types for OpenAPI-migrated endpoints must remain commented out.
Applied to files:
apps/meteor/app/api/server/definition.tsdocs/api-endpoint-migration.mdpackages/rest-typings/src/v1/directory.tsapps/meteor/app/api/server/v1/misc.tsapps/meteor/client/views/directory/tabs/users/UsersTable/UsersTableRow.tsxapps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsxapps/meteor/app/api/server/v1/cloud.tsapps/meteor/app/api/server/v1/roles.tsapps/meteor/app/api/server/v1/email-inbox.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/assets.tsapps/meteor/app/api/server/v1/integrations.tsapps/meteor/app/api/server/v1/settings.tsapps/meteor/app/api/server/v1/moderation.tsapps/meteor/app/api/server/v1/autotranslate.ts
📚 Learning: 2026-02-24T19:09:09.561Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:09.561Z
Learning: In RocketChat/Rocket.Chat OpenAPI migration PRs for apps/meteor/app/api/server/v1 endpoints, maintainers prefer to avoid any logic changes; style-only cleanups (like removing inline comments) may be deferred to follow-ups to keep scope tight.
Applied to files:
docs/api-endpoint-migration.md
📚 Learning: 2026-03-10T08:13:52.153Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 39414
File: apps/meteor/app/api/server/v1/rooms.ts:1241-1297
Timestamp: 2026-03-10T08:13:52.153Z
Learning: In the RocketChat/Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1/rooms.ts, the pattern `ajv.compile<void>({...})` is intentionally used for the 200 response schema even when the endpoint returns `{ success: true }`. This is an established convention across all migrated endpoints (rooms.leave, rooms.favorite, rooms.delete, rooms.muteUser, rooms.unmuteUser). Do not flag this as a type mismatch during reviews of these migration PRs.
Applied to files:
docs/api-endpoint-migration.mdpackages/rest-typings/src/v1/directory.tsapps/meteor/app/api/server/v1/misc.tsapps/meteor/app/api/server/v1/videoConference.tsapps/meteor/app/api/server/v1/cloud.tsapps/meteor/app/api/server/v1/banners.tsapps/meteor/app/api/server/v1/roles.tsapps/meteor/app/api/server/v1/email-inbox.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/assets.tspackages/core-typings/src/Ajv.tsapps/meteor/app/api/server/v1/integrations.tsapps/meteor/app/api/server/v1/moderation.tsapps/meteor/app/api/server/v1/e2e.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/rest-typings/src/v1/directory.ts
📚 Learning: 2025-11-27T17:56:26.050Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37557
File: apps/meteor/client/views/admin/ABAC/AdminABACRooms.tsx:115-116
Timestamp: 2025-11-27T17:56:26.050Z
Learning: In Rocket.Chat, the GET /v1/abac/rooms endpoint (implemented in ee/packages/abac/src/index.ts) only returns rooms where abacAttributes exists and is not an empty array (query: { abacAttributes: { $exists: true, $ne: [] } }). Therefore, in components consuming this endpoint (like AdminABACRooms.tsx), room.abacAttributes is guaranteed to be defined for all returned rooms, and optional chaining before calling array methods like .join() is sufficient without additional null coalescing.
Applied to files:
packages/rest-typings/src/v1/directory.tspackages/core-typings/src/IRoom.ts
📚 Learning: 2026-02-24T19:09:01.522Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:01.522Z
Learning: In Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1, avoid introducing logic changes. Only perform scope-tight changes that preserve behavior; style-only cleanups (e.g., removing inline comments) may be deferred to follow-ups to keep the migration PR focused.
Applied to files:
apps/meteor/app/api/server/v1/misc.tsapps/meteor/app/api/server/v1/videoConference.tsapps/meteor/app/api/server/v1/cloud.tsapps/meteor/app/api/server/v1/banners.tsapps/meteor/app/api/server/v1/roles.tsapps/meteor/app/api/server/v1/email-inbox.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/assets.tsapps/meteor/app/api/server/v1/integrations.tsapps/meteor/app/api/server/v1/calendar.tsapps/meteor/app/api/server/v1/settings.tsapps/meteor/app/api/server/v1/moderation.tsapps/meteor/app/api/server/v1/autotranslate.tsapps/meteor/app/api/server/v1/e2e.ts
📚 Learning: 2025-10-16T21:09:51.816Z
Learnt from: cardoso
Repo: RocketChat/Rocket.Chat PR: 36942
File: apps/meteor/client/lib/e2ee/keychain.ts:148-156
Timestamp: 2025-10-16T21:09:51.816Z
Learning: In the RocketChat/Rocket.Chat repository, only platforms with native crypto.randomUUID() support are targeted, so fallback implementations for crypto.randomUUID() are not required in E2EE or cryptographic code.
Applied to files:
apps/meteor/app/api/server/v1/misc.ts
📚 Learning: 2026-02-23T17:53:06.802Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:06.802Z
Learning: During PR reviews that touch endpoint files under apps/meteor/app/api/server/v1, enforce strict scope: if a PR targets a specific endpoint (e.g., rooms.favorite), do not propose changes to unrelated endpoints (e.g., rooms.invite) unless maintainers explicitly request them. Focus feedback on the touched endpoint's behavior, API surface, and related tests; avoid broad cross-endpoint changes in the same PR unless requested.
Applied to files:
apps/meteor/app/api/server/v1/misc.tsapps/meteor/app/api/server/v1/videoConference.tsapps/meteor/app/api/server/v1/cloud.tsapps/meteor/app/api/server/v1/banners.tsapps/meteor/app/api/server/v1/roles.tsapps/meteor/app/api/server/v1/email-inbox.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/assets.tsapps/meteor/app/api/server/v1/integrations.tsapps/meteor/app/api/server/v1/calendar.tsapps/meteor/app/api/server/v1/settings.tsapps/meteor/app/api/server/v1/moderation.tsapps/meteor/app/api/server/v1/autotranslate.tsapps/meteor/app/api/server/v1/e2e.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `expect` matchers for assertions (`toEqual`, `toContain`, `toBeTruthy`, `toHaveLength`, etc.) instead of `assert` statements in Playwright tests
Applied to files:
apps/meteor/tests/end-to-end/api/outgoing-integrations.tsapps/meteor/tests/end-to-end/api/livechat/11-email-inbox.tsapps/meteor/tests/end-to-end/api/cloud.tsapps/meteor/tests/end-to-end/api/banners.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts
Applied to files:
apps/meteor/tests/end-to-end/api/outgoing-integrations.tsapps/meteor/tests/end-to-end/api/livechat/11-email-inbox.tsapps/meteor/tests/end-to-end/api/cloud.tsapps/meteor/tests/end-to-end/api/banners.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Utilize Playwright fixtures (`test`, `page`, `expect`) for consistency in test files
Applied to files:
apps/meteor/tests/end-to-end/api/outgoing-integrations.tsapps/meteor/tests/end-to-end/api/cloud.tsapps/meteor/tests/end-to-end/api/banners.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Prefer web-first assertions (`toBeVisible`, `toHaveText`, etc.) in Playwright tests
Applied to files:
apps/meteor/tests/end-to-end/api/outgoing-integrations.tsapps/meteor/tests/end-to-end/api/cloud.tsapps/meteor/tests/end-to-end/api/banners.ts
📚 Learning: 2025-12-16T17:29:45.163Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37834
File: apps/meteor/tests/e2e/page-objects/fragments/admin-flextab-emoji.ts:12-22
Timestamp: 2025-12-16T17:29:45.163Z
Learning: In page object files under `apps/meteor/tests/e2e/page-objects/`, always import `expect` from `../../utils/test` (Playwright's async expect), not from Jest. Jest's `expect` has a synchronous signature and will cause TypeScript errors when used with web-first assertions like `toBeVisible()`.
Applied to files:
apps/meteor/tests/end-to-end/api/outgoing-integrations.tsapps/meteor/tests/end-to-end/api/banners.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `test.step()` for complex test scenarios to improve organization in Playwright tests
Applied to files:
apps/meteor/tests/end-to-end/api/outgoing-integrations.tsapps/meteor/tests/end-to-end/api/banners.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Maintain test isolation between test cases in Playwright tests
Applied to files:
apps/meteor/tests/end-to-end/api/outgoing-integrations.tsapps/meteor/tests/end-to-end/api/livechat/11-email-inbox.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to **/*.spec.ts : Use descriptive test names that clearly communicate expected behavior in Playwright tests
Applied to files:
apps/meteor/tests/end-to-end/api/outgoing-integrations.ts
📚 Learning: 2025-12-10T21:00:54.909Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37091
File: ee/packages/abac/jest.config.ts:4-7
Timestamp: 2025-12-10T21:00:54.909Z
Learning: Rocket.Chat monorepo: Jest testMatch pattern '<rootDir>/src/**/*.spec.(ts|js|mjs)' is valid in this repo and used across multiple packages (e.g., packages/tools, ee/packages/omnichannel-services). Do not flag it as invalid in future reviews.
Applied to files:
apps/meteor/tests/end-to-end/api/outgoing-integrations.tsapps/meteor/tests/end-to-end/api/livechat/11-email-inbox.tsapps/meteor/tests/end-to-end/api/cloud.tsapps/meteor/tests/end-to-end/api/banners.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : All test files must be created in `apps/meteor/tests/e2e/` directory
Applied to files:
apps/meteor/tests/end-to-end/api/outgoing-integrations.tsapps/meteor/tests/end-to-end/api/cloud.tsapps/meteor/tests/end-to-end/api/banners.ts
📚 Learning: 2026-03-11T16:46:50.707Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 39535
File: apps/meteor/app/apps/server/bridges/livechat.ts:249-249
Timestamp: 2026-03-11T16:46:50.707Z
Learning: In `apps/meteor/app/apps/server/bridges/livechat.ts`, `createVisitor()` intentionally does not propagate `externalIds` to `registerData`. This is by design: the method is deprecated (JSDoc: `deprecated Use createAndReturnVisitor instead. Note: This method does not support externalIds.`) to push callers toward `createAndReturnVisitor()`, which does support `externalIds`. Do not flag the missing `externalIds` field in `createVisitor()` as a bug.
Applied to files:
apps/meteor/tests/end-to-end/api/incoming-integrations.ts
📚 Learning: 2025-10-06T20:32:23.658Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37152
File: packages/apps-engine/tests/test-data/utilities.ts:557-573
Timestamp: 2025-10-06T20:32:23.658Z
Learning: In packages/apps-engine/tests/test-data/utilities.ts, the field name `isSubscripbedViaBundle` in the `IMarketplaceSubscriptionInfo` type should not be flagged as a typo, as it may match the upstream API's field name.
Applied to files:
apps/meteor/tests/end-to-end/api/incoming-integrations.tsapps/meteor/tests/end-to-end/api/cloud.tsapps/meteor/tests/end-to-end/api/banners.ts
📚 Learning: 2026-02-24T19:36:55.089Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 38493
File: apps/meteor/tests/e2e/page-objects/fragments/home-content.ts:60-82
Timestamp: 2026-02-24T19:36:55.089Z
Learning: In RocketChat/Rocket.Chat e2e tests (apps/meteor/tests/e2e/page-objects/fragments/home-content.ts), thread message preview listitems do not have aria-roledescription="message", so lastThreadMessagePreview locator cannot be scoped to messageListItems (which filters for aria-roledescription="message"). It should remain scoped to page.getByRole('listitem') or mainMessageList.getByRole('listitem').
Applied to files:
apps/meteor/tests/end-to-end/api/livechat/11-email-inbox.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Group related tests in the same file
Applied to files:
apps/meteor/tests/end-to-end/api/cloud.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/api/server/v1/roles.ts
📚 Learning: 2025-11-05T20:53:57.761Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: apps/meteor/ee/server/startup/federation.ts:39-74
Timestamp: 2025-11-05T20:53:57.761Z
Learning: In Rocket.Chat (apps/meteor/app/settings/server/CachedSettings.ts), the settings.watchMultiple() method immediately invokes its callback with current values if all requested settings exist in the store, then continues watching for subsequent changes. It does not wait for a setting to change before the first invocation.
Applied to files:
apps/meteor/app/api/server/v1/assets.tsapps/meteor/app/api/server/v1/settings.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:
apps/meteor/app/api/server/v1/settings.ts
📚 Learning: 2025-11-19T12:32:29.696Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37547
File: packages/i18n/src/locales/en.i18n.json:634-634
Timestamp: 2025-11-19T12:32:29.696Z
Learning: Repo: RocketChat/Rocket.Chat
Context: i18n workflow
Learning: In this repository, new translation keys should be added to packages/i18n/src/locales/en.i18n.json only; other locale files are populated via the external translation pipeline and/or fall back to English. Do not request adding the same key to all locale files in future reviews.
Applied to files:
apps/meteor/app/api/server/v1/autotranslate.ts
📚 Learning: 2025-11-19T18:20:07.720Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: packages/i18n/src/locales/en.i18n.json:918-921
Timestamp: 2025-11-19T18:20:07.720Z
Learning: Repo: RocketChat/Rocket.Chat — i18n/formatting
Learning: This repository uses a custom message formatting parser in UI blocks/messages; do not assume standard Markdown rules. For keys like Call_ended_bold, Call_not_answered_bold, Call_failed_bold, and Call_transferred_bold in packages/i18n/src/locales/en.i18n.json, retain the existing single-asterisk emphasis unless maintainers request otherwise.
Applied to files:
apps/meteor/app/api/server/v1/autotranslate.ts
🪛 Biome (2.4.6)
apps/meteor/app/api/server/v1/integrations.ts
[error] 241-241: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
(lint/correctness/noSwitchDeclarations)
[error] 262-262: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
(lint/correctness/noSwitchDeclarations)
| async function action() { | ||
| const { userId } = this; | ||
| const { id } = this.queryParams; | ||
|
|
||
| const event = await Calendar.get(id); | ||
| const event = await Calendar.get(id); | ||
|
|
||
| if (!event || event.uid !== userId) { | ||
| return API.v1.failure(); | ||
| } | ||
| if (event?.uid !== userId) { | ||
| return API.v1.failure(); | ||
| } | ||
|
|
||
| return API.v1.success({ event }); | ||
| }, | ||
| return API.v1.success({ event }); | ||
| }, |
There was a problem hiding this comment.
Inconsistent error handling: API.v1.failure() vs throw new Error().
The calendar-events.info endpoint returns API.v1.failure() (Line 95) when access is denied, but calendar-events.update (Line 182) and calendar-events.delete (Line 217) throw new Error('invalid-calendar-event') for the same condition.
This inconsistency may lead to different HTTP status codes and error response shapes. Consider unifying the approach:
Option 1: Use API.v1.failure consistently
// In calendar-events.update (lines 181-183)
if (event?.uid !== userId) {
- throw new Error('invalid-calendar-event');
+ return API.v1.failure('invalid-calendar-event');
}
// In calendar-events.delete (lines 216-218)
if (event?.uid !== userId) {
- throw new Error('invalid-calendar-event');
+ return API.v1.failure('invalid-calendar-event');
}Option 2: Add error message to info endpoint
// In calendar-events.info (line 95)
if (event?.uid !== userId) {
- return API.v1.failure();
+ return API.v1.failure('invalid-calendar-event');
}📝 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.
| async function action() { | |
| const { userId } = this; | |
| const { id } = this.queryParams; | |
| const event = await Calendar.get(id); | |
| const event = await Calendar.get(id); | |
| if (!event || event.uid !== userId) { | |
| return API.v1.failure(); | |
| } | |
| if (event?.uid !== userId) { | |
| return API.v1.failure(); | |
| } | |
| return API.v1.success({ event }); | |
| }, | |
| return API.v1.success({ event }); | |
| }, | |
| async function action() { | |
| const { userId } = this; | |
| const { id } = this.queryParams; | |
| const event = await Calendar.get(id); | |
| if (event?.uid !== userId) { | |
| return API.v1.failure('invalid-calendar-event'); | |
| } | |
| return API.v1.success({ event }); | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/meteor/app/api/server/v1/calendar.ts` around lines 88 - 99, The info
action in calendar-events (function action calling Calendar.get) returns
API.v1.failure() when access is denied but the update/delete handlers throw new
Error('invalid-calendar-event'), causing inconsistent error shapes; choose one
approach and make them consistent: either change the info handler to throw new
Error('invalid-calendar-event') when event?.uid !== userId, or update the
update/delete handlers to return API.v1.failure({ error:
'invalid-calendar-event' })/API.v1.failure() as the other endpoints do; locate
the access check in action(), Calendar.get usage, and the throw sites
('invalid-calendar-event') to apply the same response pattern across
calendar-events.info, calendar-events.update, and calendar-events.delete.
| 200: ajv.compile<IEmailInbox | null>({ | ||
| oneOf: [ | ||
| { | ||
| allOf: [ | ||
| { $ref: '#/components/schemas/IEmailInbox' }, | ||
| { | ||
| type: 'object', | ||
| properties: { | ||
| success: { type: 'boolean', enum: [true] }, | ||
| }, | ||
| required: ['success'], | ||
| }, | ||
| ], | ||
| }, | ||
| { type: 'null' }, | ||
| ], | ||
| }), |
There was a problem hiding this comment.
Response schema includes null but endpoint returns 404 for missing inbox.
The 200 response schema (line 121) types the response as IEmailInbox | null with a { type: 'null' } option in oneOf. However, the handler returns API.v1.notFound() (line 151) when the inbox doesn't exist, which triggers a 404 response—not a 200 with null. The null branch in the schema will never match a successful 200 response.
🔧 Suggested fix: Remove the null branch from 200 schema
- 200: ajv.compile<IEmailInbox | null>({
- oneOf: [
- {
- allOf: [
- { $ref: '#/components/schemas/IEmailInbox' },
- {
- type: 'object',
- properties: {
- success: { type: 'boolean', enum: [true] },
- },
- required: ['success'],
- },
- ],
- },
- { type: 'null' },
- ],
- }),
+ 200: ajv.compile<IEmailInbox>({
+ allOf: [
+ { $ref: '#/components/schemas/IEmailInbox' },
+ {
+ type: 'object',
+ properties: {
+ success: { type: 'boolean', enum: [true] },
+ },
+ required: ['success'],
+ },
+ ],
+ }),Also applies to: 150-152
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/meteor/app/api/server/v1/email-inbox.ts` around lines 121 - 137, The 200
response schema currently allows IEmailInbox | null but the handler returns
API.v1.notFound() (404) for missing inboxes so the null branch is unreachable;
update the ajv.compile call that builds the 200 schema to remove the { type:
'null' } branch and the surrounding oneOf so the response schema only validates
IEmailInbox (referencing IEmailInbox in the schema), and ensure no code paths
expect a 200 null—keep API.v1.notFound() for missing inboxes (adjust any related
type annotations if necessary).
| const spotlightResponseSchema = ajv.compile<{ | ||
| users: Pick<IUser, 'name' | 'status' | 'statusText' | 'avatarETag' | '_id' | 'username'>[]; | ||
| rooms: Pick<IRoom, 't' | 'name' | 'lastMessage' | '_id'>[]; | ||
| }>({ | ||
| type: 'object', | ||
| properties: { | ||
| users: { | ||
| type: 'array', | ||
| items: { | ||
| type: 'object', | ||
| properties: { | ||
| _id: { type: 'string' }, | ||
| name: { type: 'string' }, | ||
| username: { type: 'string' }, | ||
| status: { type: 'string' }, | ||
| statusText: { type: 'string' }, | ||
| avatarETag: { type: 'string' }, | ||
| }, | ||
| required: ['_id', 'name', 'username', 'status', 'statusText'], | ||
| additionalProperties: true, | ||
| }, | ||
| }, | ||
| rooms: { | ||
| type: 'array', | ||
| items: { | ||
| type: 'object', | ||
| properties: { | ||
| _id: { type: 'string' }, | ||
| t: { type: 'string' }, | ||
| name: { type: 'string' }, | ||
| lastMessage: { type: 'object' }, | ||
| }, | ||
| required: ['_id', 't', 'name'], | ||
| additionalProperties: true, | ||
| }, | ||
| }, | ||
| success: { type: 'boolean', enum: [true] }, | ||
| }, | ||
| required: ['users', 'rooms', 'success'], | ||
| additionalProperties: false, | ||
| }); |
There was a problem hiding this comment.
Keep optional spotlight fields out of required.
name and statusText are optional on the selected IUser shape, but this schema now makes both mandatory. A valid spotlight result for a user without one of those fields will start failing response validation.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/meteor/app/api/server/v1/misc.ts` around lines 333 - 373, The users item
schema in spotlightResponseSchema wrongly marks optional IUser fields as
required — remove "name" and "statusText" from the users.items.required array
(keep _id, username, status if those are truly required) so that a user object
missing name or statusText still validates; reference the
spotlightResponseSchema variable and the users/ users.items.required entries
when making the change.
| response: { | ||
| 200: methodCallResponseSchema, | ||
| 400: methodCallErrorResponseSchema, | ||
| 401: validateUnauthorizedErrorResponse, | ||
| 429: ajv.compile({ | ||
| type: 'object', | ||
| properties: { success: { type: 'boolean', enum: [false] }, error: { type: 'string' } }, | ||
| required: ['success'], | ||
| additionalProperties: true, | ||
| }), |
There was a problem hiding this comment.
The declared 429 branch is unreachable.
The rate-limit Meteor.Error is thrown inside the try, then the broad catch always converts it to API.v1.failure(mountResult(...)). Clients will still receive the generic method-call failure payload, not the new 429 response.
Also applies to: 639-659
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/meteor/app/api/server/v1/misc.ts` around lines 603 - 612, The 429
response schema is never used because the broad catch converts rate-limit
Meteor.Error into API.v1.failure(mountResult(...)); update the catch logic to
detect the rate-limit error (check for Meteor.Error or its identifying fields)
and, when matched, call API.v1.failure(mountResult(...), 429) or otherwise
return the mounted 429 payload instead of the generic failure; adjust the catch
in the same handler that references
methodCallResponseSchema/methodCallErrorResponseSchema so the rate-limit branch
becomes reachable and leave other errors to continue using the existing
API.v1.failure behavior.
| .get( | ||
| 'roles.getUsersInPublicRoles', | ||
| { | ||
| authRequired: true, | ||
| response: { | ||
| 200: ajv.compile<{ | ||
| users: { | ||
| type: 'array', | ||
| items: { | ||
| type: 'object', | ||
| properties: { _id: { type: 'string' }, username: { type: 'string' }, roles: { type: 'array', items: { type: 'string' } } }, | ||
| _id: string; | ||
| username: string; | ||
| roles: string[]; | ||
| }[]; | ||
| }>({ | ||
| type: 'object', | ||
| properties: { | ||
| users: { | ||
| type: 'array', | ||
| items: { | ||
| type: 'object', | ||
| properties: { | ||
| _id: { type: 'string' }, | ||
| username: { type: 'string' }, | ||
| roles: { type: 'array', items: { type: 'string' } }, | ||
| }, | ||
| }, | ||
| }, | ||
| success: { type: 'boolean', enum: [true] }, | ||
| }, | ||
| }, | ||
| }), | ||
| required: ['users', 'success'], | ||
| additionalProperties: false, | ||
| }), | ||
| }, |
There was a problem hiding this comment.
Add the missing 401 response mapping.
This route is authRequired: true, but its response map only declares 200. Unauthenticated requests now fall outside the new contract for the endpoint.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/meteor/app/api/server/v1/roles.ts` around lines 311 - 341, The route
handler for 'roles.getUsersInPublicRoles' sets authRequired: true but the
response schema only declares 200; add a 401 response mapping under the same
response object to declare the unauthenticated response shape (e.g., an error
object with success: false and an error/message field) so the route contract
covers unauthenticated requests; update the response block associated with
'roles.getUsersInPublicRoles' to include this 401 AJV schema alongside the
existing 200 schema.
| API.v1.get( | ||
| 'settings.public', | ||
| { authRequired: false, validateParams: isSettingsPublicWithPaginationProps }, | ||
| { | ||
| async get() { | ||
| const { offset, count } = await getPaginationItems(this.queryParams); | ||
| const { sort, fields, query } = await this.parseJsonQuery(); | ||
| const { _id } = this.queryParams; | ||
|
|
||
| const parsedQueryId = typeof _id === 'string' && _id ? { _id: { $in: _id.split(',').map((id) => id.trim()) } } : {}; | ||
|
|
||
| const ourQuery = { | ||
| ...query, | ||
| ...parsedQueryId, | ||
| hidden: { $ne: true }, | ||
| public: true, | ||
| }; | ||
|
|
||
| const { settings, totalCount: total } = await fetchSettings(ourQuery, sort, offset, count, fields); | ||
|
|
||
| return API.v1.success({ | ||
| settings, | ||
| count: settings.length, | ||
| offset, | ||
| total, | ||
| }); | ||
| authRequired: false, | ||
| query: isSettingsPublicWithPaginationProps, | ||
| response: { | ||
| 200: settingsPublicResponseSchema, | ||
| }, | ||
| }, | ||
| async function action() { | ||
| const { offset, count } = await getPaginationItems(this.queryParams); | ||
| const { sort, fields, query } = await this.parseJsonQuery(); | ||
| const { _id } = this.queryParams; | ||
|
|
||
| const parsedQueryId = typeof _id === 'string' && _id ? { _id: { $in: _id.split(',').map((id) => id.trim()) } } : {}; | ||
|
|
||
| const ourQuery = { | ||
| ...query, | ||
| ...parsedQueryId, | ||
| hidden: { $ne: true }, | ||
| public: true, | ||
| }; | ||
|
|
||
| const { settings: settingsList, totalCount: total } = await fetchSettings(ourQuery, sort, offset, count, fields); | ||
|
|
||
| return API.v1.success({ | ||
| settings: settingsList, | ||
| count: settingsList.length, | ||
| offset, | ||
| total, | ||
| }); | ||
| }, | ||
| ); |
There was a problem hiding this comment.
Keep the bad-request path in both settings route maps.
Both handlers validate query params and call parseJsonQuery(), so malformed sort, fields, or query inputs still produce 400s. The new response maps omit that status, leaving those failures outside the route contract.
Also applies to: 243-280
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/meteor/app/api/server/v1/settings.ts` around lines 137 - 169, The route
response map for API.v1.get('settings.public') (which uses
isSettingsPublicWithPaginationProps and calls parseJsonQuery) is missing a 400
response entry for malformed sort/fields/query payloads; update the route's
response object to include a 400 entry (using the existing
bad-request/validation error response schema used elsewhere) so validation
failures are part of the contract, and make the same change to the other
settings route that also calls parseJsonQuery (the second settings handler
referenced in the review).
| API.v1.post( | ||
| 'settings.addCustomOAuth', | ||
| { authRequired: true, twoFactorRequired: true }, | ||
| { | ||
| async post() { | ||
| if (!this.bodyParams.name?.trim()) { | ||
| throw new Meteor.Error('error-name-param-not-provided', 'The parameter "name" is required'); | ||
| } | ||
| authRequired: true, | ||
| twoFactorRequired: true, | ||
| body: addCustomOAuthBodySchema, | ||
| response: { | ||
| 200: ajv.compile<void>({ | ||
| type: 'object', | ||
| properties: { success: { type: 'boolean', enum: [true] } }, | ||
| required: ['success'], | ||
| additionalProperties: false, | ||
| }), | ||
| 400: ajv.compile({ | ||
| type: 'object', | ||
| properties: { success: { type: 'boolean', enum: [false] }, error: { type: 'string' } }, | ||
| required: ['success'], | ||
| additionalProperties: false, | ||
| }), | ||
| 401: validateUnauthorizedErrorResponse, | ||
| }, | ||
| }, | ||
| async function action() { | ||
| const { name } = this.bodyParams; | ||
| if (!name?.trim()) { | ||
| throw new Meteor.Error('error-name-param-not-provided', 'The parameter "name" is required'); | ||
| } | ||
|
|
||
| await addOAuthServiceMethod(this.userId, this.bodyParams.name); | ||
| await addOAuthServiceMethod(this.userId, name); | ||
|
|
||
| return API.v1.success(); | ||
| }, | ||
| return API.v1.success(); |
There was a problem hiding this comment.
The 400 schema here is narrower than the route's real failures.
Body-validation errors and error-name-param-not-provided include errorType, but this schema only allows success and error. Those bad-request responses will fail validation.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/meteor/app/api/server/v1/settings.ts` around lines 209 - 239, The 400
response schema for the API.v1.post('settings.addCustomOAuth') route is too
strict and doesn't allow errorType (used by body-validation and the
'error-name-param-not-provided' Meteor.Error), causing real 400 responses to
fail schema validation; update the 400 response schema in this route (near
addCustomOAuthBodySchema and the action that calls addOAuthServiceMethod) to
either include an optional errorType property (e.g., properties: { success,
error, errorType }) or allow additionalProperties so that errorType is accepted,
ensuring actual bad-request responses validate.
| Migrated endpoints **must always be chained** when a file registers multiple endpoints. Store the result in a variable, then use `ExtractRoutesFromAPI` to extract the route types and augment the `Endpoints` interface in `rest-typings`. This is what makes the endpoints fully typed across the entire codebase (SDK, client, tests). | ||
|
|
There was a problem hiding this comment.
Narrow the type-coverage claim around Endpoints augmentation.
This section currently reads as if the declare module '@rocket.chat/rest-typings' augmentation makes migrated routes visible to the whole monorepo, including SDK consumers. In this repo, augmentations declared under apps/meteor are not visible when packages/ddp-client is compiled in isolation, so phrases like “entire codebase (SDK, client, tests)” and “SDK, client hooks, and tests see these routes” are too broad. Please document that limitation or scope the claim to the packages that actually consume the augmentation.
Based on learnings: In the RocketChat/Rocket.Chat monorepo, packages/ddp-client and apps/meteor do not use TypeScript project references, so module augmentations in apps/meteor are not visible when compiling packages/ddp-client in isolation.
Also applies to: 464-489
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/api-endpoint-migration.md` around lines 408 - 409, Update the wording to
narrow the claim about module augmentations so it only asserts visibility for
packages that actually consume the augmentation (e.g., the packages compiled
together with the augmentation), and add a brief note that augmentations
declared in apps/meteor (the declare module '@rocket.chat/rest-typings'
augmentation) are not visible to packages built in isolation (for example
packages/ddp-client) because project references are not used; keep the guidance
about chaining endpoints and using ExtractRoutesFromAPI and augmenting the
Endpoints interface but explicitly state this only makes routes fully typed for
consumers that share the same compilation context, and add an analogous
clarification where the same claim appears in lines 464-489.
f5de26e
a065bd8 to
f5de26e
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
docs/api-endpoint-migration.md (1)
424-426: Add a language identifier to the fenced code block.The error message example should have a language identifier (e.g.,
textorplaintext) to satisfy markdown linting rules and improve readability.📝 Suggested fix
-``` +```text must match exactly one schema in oneOf (passingSchemas: 0,1)</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@docs/api-endpoint-migration.mdaround lines 424 - 426, The fenced code block
containing the error message "must match exactly one schema in oneOf
(passingSchemas: 0,1)" lacks a language identifier; update that code fence to
include a language specifier (for example change the openingtotext orlinting/formatting rules.apps/meteor/app/api/server/v1/moderation.ts (1)
363-373: Consider separating historical report emails from current user emails.The endpoint overwrites
user.emails(fetched from the Users collection at line 349) with emails collected from historical reports (lines 365-372). This conflates current user data with historical snapshots captured when reports were filed.If the goal is to show emails as they were when reports were created, store them in a separate field like
reportedEmailsinstead. This clarifies the API contract: consumers can then distinguish between the user's current emails and historical emails from reports.Note: The type definition includes a comment "we're assuming neither Room Info or User Info changes," suggesting this design is intentional but represents a known limitation.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/app/api/server/v1/moderation.ts` around lines 363 - 373, The code currently overwrites user.emails with emails extracted from reports (see the emailSet variable and the reports.forEach block), which mixes historical report snapshots with current user data; instead, collect those report emails into a new field (e.g., reportedEmails) on the returned user object rather than assigning to user.emails — leave user.emails untouched, set user.reportedEmails = Array.from(emailSet.values()) (or similar) so consumers can distinguish current emails from historical report emails.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/meteor/app/api/server/v1/import.ts`:
- Around line 178-201: The response schema for the getLatestImportOperations
route is wrong because API.v1.success(operations) wraps the array, so update the
200 response schema (the ajv.compile block in the getLatestImportOperations
route) to validate an object with success: true and data containing the array of
imports (i.e., { type: "object", properties: { success: { type: "boolean" },
data: { type: "array", items: { type: "object" } } }, required:
["success","data"] }), ensuring it matches the shape returned by API.v1.success;
this change applies to the route handler that calls
executeGetLatestImportOperations.
---
Nitpick comments:
In `@apps/meteor/app/api/server/v1/moderation.ts`:
- Around line 363-373: The code currently overwrites user.emails with emails
extracted from reports (see the emailSet variable and the reports.forEach
block), which mixes historical report snapshots with current user data; instead,
collect those report emails into a new field (e.g., reportedEmails) on the
returned user object rather than assigning to user.emails — leave user.emails
untouched, set user.reportedEmails = Array.from(emailSet.values()) (or similar)
so consumers can distinguish current emails from historical report emails.
In `@docs/api-endpoint-migration.md`:
- Around line 424-426: The fenced code block containing the error message "must
match exactly one schema in oneOf (passingSchemas: 0,1)" lacks a language
identifier; update that code fence to include a language specifier (for example
change the opening ``` to ```text or ```plaintext) so the block reads with a
language tag and satisfies markdown linting/formatting rules.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c2813721-d994-4aa2-a850-74ce0090c0d9
📒 Files selected for processing (9)
apps/meteor/app/api/server/definition.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/misc.tsapps/meteor/app/api/server/v1/moderation.tsdocs/api-endpoint-migration.mdpackages/core-typings/src/Ajv.tspackages/http-router/src/Router.spec.tspackages/http-router/src/Router.tspackages/models/src/models/ModerationReports.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/http-router/src/Router.spec.ts
- packages/models/src/models/ModerationReports.ts
- packages/http-router/src/Router.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: CodeQL-Build
- GitHub Check: CodeQL-Build
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation
Files:
apps/meteor/app/api/server/definition.tsapps/meteor/app/api/server/v1/misc.tspackages/core-typings/src/Ajv.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/moderation.ts
🧠 Learnings (18)
📓 Common learnings
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:09.561Z
Learning: In RocketChat/Rocket.Chat OpenAPI migration PRs for apps/meteor/app/api/server/v1 endpoints, maintainers prefer to avoid any logic changes; style-only cleanups (like removing inline comments) may be deferred to follow-ups to keep scope tight.
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 39414
File: apps/meteor/app/api/server/v1/rooms.ts:1241-1297
Timestamp: 2026-03-10T08:13:52.153Z
Learning: In the RocketChat/Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1/rooms.ts, the pattern `ajv.compile<void>({...})` is intentionally used for the 200 response schema even when the endpoint returns `{ success: true }`. This is an established convention across all migrated endpoints (rooms.leave, rooms.favorite, rooms.delete, rooms.muteUser, rooms.unmuteUser). Do not flag this as a type mismatch during reviews of these migration PRs.
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:18.785Z
Learning: In Rocket.Chat PR reviews, maintain strict scope boundaries—when a PR is focused on a specific endpoint (e.g., rooms.favorite), avoid reviewing or suggesting changes to other endpoints that were incidentally refactored (e.g., rooms.invite) unless explicitly requested by maintainers.
📚 Learning: 2026-02-25T20:10:16.987Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38913
File: packages/ddp-client/src/legacy/types/SDKLegacy.ts:34-34
Timestamp: 2026-02-25T20:10:16.987Z
Learning: In the RocketChat/Rocket.Chat monorepo, packages/ddp-client and apps/meteor do not use TypeScript project references. Module augmentations in apps/meteor (e.g., declare module 'rocket.chat/rest-typings') are not visible when compiling packages/ddp-client in isolation, which is why legacy SDK methods that depend on OperationResult types for OpenAPI-migrated endpoints must remain commented out.
Applied to files:
apps/meteor/app/api/server/definition.tsapps/meteor/app/api/server/v1/misc.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/moderation.tsdocs/api-endpoint-migration.md
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.
Applied to files:
apps/meteor/app/api/server/definition.tsapps/meteor/app/api/server/v1/misc.tspackages/core-typings/src/Ajv.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/moderation.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.
Applied to files:
apps/meteor/app/api/server/definition.tsapps/meteor/app/api/server/v1/misc.tspackages/core-typings/src/Ajv.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/moderation.ts
📚 Learning: 2026-02-24T19:09:01.522Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:01.522Z
Learning: In Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1, avoid introducing logic changes. Only perform scope-tight changes that preserve behavior; style-only cleanups (e.g., removing inline comments) may be deferred to follow-ups to keep the migration PR focused.
Applied to files:
apps/meteor/app/api/server/v1/misc.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/moderation.ts
📚 Learning: 2026-03-10T08:13:52.153Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 39414
File: apps/meteor/app/api/server/v1/rooms.ts:1241-1297
Timestamp: 2026-03-10T08:13:52.153Z
Learning: In the RocketChat/Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1/rooms.ts, the pattern `ajv.compile<void>({...})` is intentionally used for the 200 response schema even when the endpoint returns `{ success: true }`. This is an established convention across all migrated endpoints (rooms.leave, rooms.favorite, rooms.delete, rooms.muteUser, rooms.unmuteUser). Do not flag this as a type mismatch during reviews of these migration PRs.
Applied to files:
apps/meteor/app/api/server/v1/misc.tspackages/core-typings/src/Ajv.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/moderation.tsdocs/api-endpoint-migration.md
📚 Learning: 2026-03-03T11:11:48.541Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 39230
File: apps/meteor/app/api/server/v1/chat.ts:214-222
Timestamp: 2026-03-03T11:11:48.541Z
Learning: In apps/meteor/server/lib/moderation/reportMessage.ts, the reportMessage function validates that description is not empty or whitespace-only with `if (!description.trim())`. When migrating the chat.reportMessage endpoint to OpenAPI, adding minLength validation to the schema preserves this existing behavior.
Applied to files:
apps/meteor/app/api/server/v1/misc.tsapps/meteor/app/api/server/v1/moderation.ts
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.
Applied to files:
apps/meteor/app/api/server/v1/misc.tspackages/core-typings/src/Ajv.tsapps/meteor/app/api/server/v1/moderation.tsdocs/api-endpoint-migration.md
📚 Learning: 2026-01-26T18:26:01.279Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 38227
File: apps/meteor/app/api/server/router.ts:44-49
Timestamp: 2026-01-26T18:26:01.279Z
Learning: In apps/meteor/app/api/server/router.ts, when retrieving bodyParams and queryParams from the Hono context via c.get(), do not add defensive defaults (e.g., ?? {}). The code should fail fast if these parameters are missing, as endpoint handlers expect them to be present and breaking here helps surface parsing problems rather than hiding them.
Applied to files:
apps/meteor/app/api/server/v1/misc.tsapps/meteor/app/api/server/v1/import.tsdocs/api-endpoint-migration.md
📚 Learning: 2026-03-11T16:46:50.707Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 39535
File: apps/meteor/app/apps/server/bridges/livechat.ts:249-249
Timestamp: 2026-03-11T16:46:50.707Z
Learning: In `apps/meteor/app/apps/server/bridges/livechat.ts`, `createVisitor()` intentionally does not propagate `externalIds` to `registerData`. This is by design: the method is deprecated (JSDoc: `deprecated Use createAndReturnVisitor instead. Note: This method does not support externalIds.`) to push callers toward `createAndReturnVisitor()`, which does support `externalIds`. Do not flag the missing `externalIds` field in `createVisitor()` as a bug.
Applied to files:
apps/meteor/app/api/server/v1/misc.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/api/server/v1/misc.tsdocs/api-endpoint-migration.md
📚 Learning: 2025-10-16T21:09:51.816Z
Learnt from: cardoso
Repo: RocketChat/Rocket.Chat PR: 36942
File: apps/meteor/client/lib/e2ee/keychain.ts:148-156
Timestamp: 2025-10-16T21:09:51.816Z
Learning: In the RocketChat/Rocket.Chat repository, only platforms with native crypto.randomUUID() support are targeted, so fallback implementations for crypto.randomUUID() are not required in E2EE or cryptographic code.
Applied to files:
apps/meteor/app/api/server/v1/misc.ts
📚 Learning: 2026-02-23T17:53:06.802Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:06.802Z
Learning: During PR reviews that touch endpoint files under apps/meteor/app/api/server/v1, enforce strict scope: if a PR targets a specific endpoint (e.g., rooms.favorite), do not propose changes to unrelated endpoints (e.g., rooms.invite) unless maintainers explicitly request them. Focus feedback on the touched endpoint's behavior, API surface, and related tests; avoid broad cross-endpoint changes in the same PR unless requested.
Applied to files:
apps/meteor/app/api/server/v1/misc.tsapps/meteor/app/api/server/v1/import.tsapps/meteor/app/api/server/v1/moderation.ts
📚 Learning: 2026-02-24T19:09:09.561Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:09.561Z
Learning: In RocketChat/Rocket.Chat OpenAPI migration PRs for apps/meteor/app/api/server/v1 endpoints, maintainers prefer to avoid any logic changes; style-only cleanups (like removing inline comments) may be deferred to follow-ups to keep scope tight.
Applied to files:
docs/api-endpoint-migration.md
📚 Learning: 2026-02-23T17:53:18.785Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:18.785Z
Learning: In Rocket.Chat PR reviews, maintain strict scope boundaries—when a PR is focused on a specific endpoint (e.g., rooms.favorite), avoid reviewing or suggesting changes to other endpoints that were incidentally refactored (e.g., rooms.invite) unless explicitly requested by maintainers.
Applied to files:
docs/api-endpoint-migration.md
📚 Learning: 2026-02-24T19:36:55.089Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 38493
File: apps/meteor/tests/e2e/page-objects/fragments/home-content.ts:60-82
Timestamp: 2026-02-24T19:36:55.089Z
Learning: In RocketChat/Rocket.Chat e2e tests (apps/meteor/tests/e2e/page-objects/fragments/home-content.ts), thread message preview listitems do not have aria-roledescription="message", so lastThreadMessagePreview locator cannot be scoped to messageListItems (which filters for aria-roledescription="message"). It should remain scoped to page.getByRole('listitem') or mainMessageList.getByRole('listitem').
Applied to files:
docs/api-endpoint-migration.md
📚 Learning: 2025-12-10T21:00:54.909Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37091
File: ee/packages/abac/jest.config.ts:4-7
Timestamp: 2025-12-10T21:00:54.909Z
Learning: Rocket.Chat monorepo: Jest testMatch pattern '<rootDir>/src/**/*.spec.(ts|js|mjs)' is valid in this repo and used across multiple packages (e.g., packages/tools, ee/packages/omnichannel-services). Do not flag it as invalid in future reviews.
Applied to files:
docs/api-endpoint-migration.md
📚 Learning: 2026-03-04T14:16:49.202Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39304
File: packages/ui-contexts/src/ActionManagerContext.ts:26-26
Timestamp: 2026-03-04T14:16:49.202Z
Learning: In `packages/ui-contexts/src/ActionManagerContext.ts` (TypeScript, RocketChat/Rocket.Chat), the `disposeView` method in `IActionManager` uses an intentionally explicit union `UiKit.ModalView['id'] | UiKit.BannerView['viewId'] | UiKit.ContextualBarView['id']` to document which view types are accepted, even though all constituents resolve to the same primitive. The inline `// eslint-disable-next-line typescript-eslint/no-duplicate-type-constituents` comment is intentional and should not be flagged or removed.
Applied to files:
docs/api-endpoint-migration.md
🪛 markdownlint-cli2 (0.21.0)
docs/api-endpoint-migration.md
[warning] 424-424: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (15)
apps/meteor/app/api/server/definition.ts (1)
19-22: Type constraint refinement is correct.The change from
extends objecttoextends Record<string, unknown>accurately models that API responses must be plain JSON objects, not arrays or functions. This aligns with OpenAPI standardization goals. Verification across the v1 endpoints confirms the pattern: all calls wrap results in objects, never passing bare arrays tosuccess().docs/api-endpoint-migration.md (1)
454-455: Narrow the type-coverage claim aroundEndpointsaugmentation.The phrase "entire codebase (SDK, client, tests)" overstates augmentation visibility. Module augmentations declared in
apps/meteorare not visible whenpackages/ddp-clientis compiled in isolation (no TypeScript project references). Update wording to clarify that augmentations only benefit packages sharing the same compilation context.Based on learnings: "In the RocketChat/Rocket.Chat monorepo, packages/ddp-client and apps/meteor do not use TypeScript project references. Module augmentations in apps/meteor are not visible when compiling packages/ddp-client in isolation."
apps/meteor/app/api/server/v1/misc.ts (5)
333-373: Keep optional spotlight fields out ofrequired.
nameandstatusTextare optional on the selectedIUsershape, but this schema marks both as mandatory (line 351). A valid spotlight result for a user without one of those fields will fail response validation.🛠️ Suggested fix
required: ['_id', 'name', 'username', 'status', 'statusText'], + // 'name' and 'statusText' are optional on IUser - remove from required - required: ['_id', 'name', 'username', 'status', 'statusText'], + required: ['_id', 'username', 'status'],
603-612: The declared 429 branch is unreachable.The rate-limit
Meteor.Errorthrown at lines 643-646 is caught by the broadcatchat line 649, which always returnsAPI.v1.failure(mountResult(...))with no special handling for rate-limit errors. Clients will never receive a 429 status code.To make the 429 schema meaningful, detect the rate-limit error in the catch block:
🛠️ Suggested fix
} catch (err) { + if (err instanceof Meteor.Error && err.error === 'too-many-requests') { + return API.v1.failure({ error: err.reason }, 429); + } if (!(err as any).isClientSafe && !(err as any).meteorError) { SystemLogger.error({ msg: 'Exception while invoking method', err, method }); }Also applies to: 639-659
173-194: LGTM!The
meResponseSchemawithadditionalProperties: trueis appropriate for the flexible user data structure, and the migration toAPI.v1.getwith explicit response schemas follows the new pattern correctly.
395-469: LGTM!The directory endpoint migration correctly uses
oneOfwith$reffor the union typeIDirectoryUserResult | IDirectoryChannelResult, following the documented pattern for handling union types.
747-860: LGTM!The fingerprint endpoint migration follows the established pattern with proper body validation, response schemas, and action handler. The
ajv.compile<void>pattern for success-only responses is consistent with the project convention.packages/core-typings/src/Ajv.ts (1)
25-58: LGTM!The expansion of the typia schema union to include additional types (
IBanner,ICalendarEvent,IEmailInbox,IModerationAudit,IModerationReport,IRole,IRoom,IDirectoryChannelResult,IUser,IDirectoryUserResult,VideoConferencetypes,Cloudtypes,IImport) enables$refusage in endpoint response schemas as documented in the migration guide.apps/meteor/app/api/server/v1/import.ts (2)
36-72: LGTM on the core response schemas.The
successResponseSchema,countResponseSchema, andoperationResponseSchemacorrectly include thesuccessfield and follow the established pattern.
73-136: LGTM!The endpoint migrations for
uploadImportFile,downloadPublicImportFile, andstartImportcorrectly use body validators and response schemas with proper error mappings.apps/meteor/app/api/server/v1/moderation.ts (5)
24-60: LGTM!The
paginatedReportsResponseSchemacorrectly documents theDate | stringissue with a TODO comment (as recommended in the migration guide) and uses a relaxed inline schema. The required fields match the projection fromfindMessageReportsGroupedByUser(context snippet 1).
62-96: LGTM!The
paginatedUserReportsResponseSchemarequired fields (reportedUser,ts,count) match the projection fromfindUserReportsaggregation pipeline (context snippet 3).
269-321: LGTM!The message deduplication logic using a
Setto track visited message IDs is a clean approach to avoid returning duplicate messages in the response.
591-621: LGTM!The
moderation.reportUserendpoint correctly validates the reported user exists before creating the report, and passes the appropriate user fields tocreateWithDescriptionAndUsermatching the expectedreportedBytype fromIModerationReport.
249-265:⚠️ Potential issue | 🟠 MajorType cast masks structural mismatch between actual and declared response schema.
findUserReportsreturnsPick<UserReport, '_id' | 'reportedUser' | 'ts'> & { count: number }(only 4 fields), but the response is cast toIModerationAudit[]which expects userId, username, name, message, msgId, roomIds, ts, rooms, count, and isUserDeleted. The runtime data structure is fundamentally incompatible with the declared schema. Update the response schema to match the actual aggregation projection or restructure the aggregation to populate all required IModerationAudit fields.⛔ Skipped due to learnings
Learnt from: ahmed-n-abdeltwab Repo: RocketChat/Rocket.Chat PR: 39414 File: apps/meteor/app/api/server/v1/rooms.ts:1241-1297 Timestamp: 2026-03-10T08:13:52.153Z Learning: In the RocketChat/Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1/rooms.ts, the pattern `ajv.compile<void>({...})` is intentionally used for the 200 response schema even when the endpoint returns `{ success: true }`. This is an established convention across all migrated endpoints (rooms.leave, rooms.favorite, rooms.delete, rooms.muteUser, rooms.unmuteUser). Do not flag this as a type mismatch during reviews of these migration PRs.Learnt from: ahmed-n-abdeltwab Repo: RocketChat/Rocket.Chat PR: 39230 File: apps/meteor/app/api/server/v1/chat.ts:214-222 Timestamp: 2026-03-03T11:11:48.541Z Learning: In apps/meteor/server/lib/moderation/reportMessage.ts, the reportMessage function validates that description is not empty or whitespace-only with `if (!description.trim())`. When migrating the chat.reportMessage endpoint to OpenAPI, adding minLength validation to the schema preserves this existing behavior.Learnt from: tassoevan Repo: RocketChat/Rocket.Chat PR: 38219 File: packages/core-typings/src/cloud/Announcement.ts:5-6 Timestamp: 2026-01-17T01:51:47.764Z Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.
| API.v1.get( | ||
| 'getLatestImportOperations', | ||
| { | ||
| authRequired: true, | ||
| validateParams: isGetLatestImportOperationsParamsGET, | ||
| permissionsRequired: ['view-import-operations'], | ||
| }, | ||
| { | ||
| async get() { | ||
| const result = await executeGetLatestImportOperations(); | ||
| return API.v1.success(result); | ||
| query: isGetLatestImportOperationsParamsGET, | ||
| response: { | ||
| 200: ajv.compile<Array<IImport>>({ | ||
| type: 'array', | ||
| items: { | ||
| type: 'object', | ||
| }, | ||
| }), | ||
| 400: validateBadRequestErrorResponse, | ||
| 401: validateUnauthorizedErrorResponse, | ||
| 403: validateForbiddenErrorResponse, | ||
| }, | ||
| }, | ||
| async function action() { | ||
| const operations = await executeGetLatestImportOperations(); | ||
|
|
||
| return API.v1.success(operations); | ||
| }, | ||
| ); |
There was a problem hiding this comment.
Same array schema issue as importers.list.
The schema at lines 185-190 validates a raw array, but API.v1.success(operations) wraps it with success: true. This is the same pattern issue as importersListResponseSchema.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/meteor/app/api/server/v1/import.ts` around lines 178 - 201, The response
schema for the getLatestImportOperations route is wrong because
API.v1.success(operations) wraps the array, so update the 200 response schema
(the ajv.compile block in the getLatestImportOperations route) to validate an
object with success: true and data containing the array of imports (i.e., {
type: "object", properties: { success: { type: "boolean" }, data: { type:
"array", items: { type: "object" } } }, required: ["success","data"] }),
ensuring it matches the shape returned by API.v1.success; this change applies to
the route handler that calls executeGetLatestImportOperations.
Made-with: Cursor
Made-with: Cursor
- Enhanced error messages to include specific paths for validation errors. - Updated response handling to ensure clearer feedback on invalid responses.
- Changed the success method return type to ensure it always includes a success property. - Updated the SuccessResult type to accept a broader object structure for the body.
f5de26e to
d0257b4
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (4)
docs/api-endpoint-migration.md (2)
510-535: 🛠️ Refactor suggestion | 🟠 MajorClarify augmentation scope in "What augmentation enables" section.
Similar to line 454, the comment and list here imply augmentations make routes visible to all SDK consumers, but this is only accurate for code compiled within the same TypeScript project. The "Client SDK" bullet point may be misleading for independently-compiled packages like
packages/ddp-client.Consider adding a note after the list clarifying that augmentation benefits apply to code compiled in the same context as the augmentation (e.g., within
apps/meteor), and that independently-compiled packages likeddp-clientwill not see these augmentations unless TypeScript project references are configured. Based on learnings: In the RocketChat/Rocket.Chat monorepo, packages/ddp-client and apps/meteor do not use TypeScript project references, so module augmentations in apps/meteor are not visible when compiling packages/ddp-client in isolation.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/api-endpoint-migration.md` around lines 510 - 535, Add a clarifying note after the "What augmentation enables" list stating that the module augmentation via declare module '@rocket.chat/rest-typings' (and types extracted with ExtractRoutesFromAPI/typeof myEndpoints) only takes effect for code compiled within the same TypeScript project/compilation context (so useEndpoint and api.get typed benefits apply only to consumers built together), and explicitly call out that independently-compiled packages like packages/ddp-client will not see these augmentations unless TypeScript project references or equivalent cross-package type sharing is configured.
454-454: 🛠️ Refactor suggestion | 🟠 MajorNarrow the scope claim about augmentation visibility.
The phrase "across the entire codebase (SDK, client, tests)" overstates the reach of module augmentations declared in
apps/meteor. These augmentations are only visible to code compiled in the same TypeScript project context. Based on learnings: In the RocketChat/Rocket.Chat monorepo, packages/ddp-client and apps/meteor do not use TypeScript project references, so module augmentations in apps/meteor are not visible when compiling packages/ddp-client in isolation.Consider rephrasing to clarify that augmentations make routes typed for consumers that share the same compilation context (e.g., code within apps/meteor and packages compiled alongside it), but not for independently-compiled packages like ddp-client.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/api-endpoint-migration.md` at line 454, Update the sentence that claims augmentations apply "across the entire codebase (SDK, client, tests)" to narrow the scope: state that module augmentations (when chaining migrated endpoints, storing result, and using ExtractRoutesFromAPI to augment the Endpoints interface in rest-typings) only apply to consumers compiled in the same TypeScript project/context (e.g., code within apps/meteor or packages compiled together) and are not visible to independently compiled packages like packages/ddp-client in the RocketChat monorepo that lack project references; adjust the example wording to mention apps/meteor explicitly as the augmentation declaration location and note the limitation for independently-built packages.apps/meteor/app/api/server/v1/misc.ts (2)
603-613:⚠️ Potential issue | 🟠 MajorThe 429 contract is still unreachable in both method-call handlers.
The rate-limit
Meteor.Erroris thrown inside thetry, but bothcatchblocks immediately normalize it toAPI.v1.failure(...), so callers still get the generic 400 payload instead of 429. Once that case is preserved,method.callAnon/:methodalso needs a 429 response mapping.Also applies to: 639-659, 671-719
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/app/api/server/v1/misc.ts` around lines 603 - 613, The 429 schema is unreachable because rate-limit Meteor.Error thrown inside the try is being normalized to API.v1.failure in the catch blocks for the method handlers; update the catch logic in the method.call/:method and method.callAnon/:method handlers to detect the rate-limit Meteor.Error (check for the Meteor.Error instance and its rate-limit identifying fields, e.g. error code/string or numeric 429) and preserve it by either rethrowing it or by returning a response with HTTP status 429 (rather than the generic 400), and ensure you add the same 429 response mapping to the method.callAnon/:method responses block so the OpenAPI contract matches the runtime behavior.
333-373:⚠️ Potential issue | 🟠 MajorKeep optional spotlight fields out of
required.Line 351 makes
nameandstatusTextmandatory, but spotlight user hits can legitimately omit those fields. This schema will reject valid responses when test-mode response validation is enabled.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/app/api/server/v1/misc.ts` around lines 333 - 373, The spotlightResponseSchema currently marks user fields "name" and "statusText" as required which rejects valid spotlight hits; update the users item schema in spotlightResponseSchema by removing "name" and "statusText" from the required array (leave only the truly mandatory fields such as "_id" and "username", and optionally "status" if you want to keep it required) so optional spotlight fields are not enforced during validation.
🧹 Nitpick comments (2)
docs/api-endpoint-migration.md (1)
424-426: Add language specifier to fenced code block.The error message example should have a language specifier for consistency.
📝 Proposed fix
-``` +```text must match exactly one schema in oneOf (passingSchemas: 0,1)</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@docs/api-endpoint-migration.mdaround lines 424 - 426, The fenced code block
containing the error message "must match exactly one schema in oneOf
(passingSchemas: 0,1)" needs a language specifier added to the opening
backticks; update the block in the docs to use a labeled fence (for example
changetotext) so the snippet is consistently highlighted as plain text.</details> </blockquote></details> <details> <summary>apps/meteor/app/api/server/v1/moderation.ts (1)</summary><blockquote> `24-29`: **Please move the repeated AJV workaround note out of the implementation.** The same TODO block is repeated five times here. A single linked issue or helper-level note would keep this migration diff smaller. As per coding guidelines `Avoid code comments in the implementation`. Also applies to: 62-67, 118-123, 151-156, 506-511 <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@apps/meteor/app/api/server/v1/moderation.ts` around lines 24 - 29, Move the repeated AJV workaround TODO about IModerationAudit.ts/Date|string out of the implementation and into a single shared location (e.g., file header comment or a dedicated migration/README helper) and replace each inline block with a short one-line pointer to that single note; specifically, consolidate the comment that explains the ts union causing AJV oneOf failures (mentions IModerationAudit, ts, AJV, and the relaxed inline schema workaround) and remove the duplicate blocks sprinkled through the implementation so only a single linked explanation remains. ``` </details> </blockquote></details> </blockquote></details> <details> <summary>🤖 Prompt for all review comments with AI agents</summary>Verify each finding against the current code and only fix it if needed.
Inline comments:
In@apps/meteor/app/api/server/v1/misc.ts:
- Around line 808-839: The code pushes a list of setting IDs into settingsIds
but never includes 'Cloud_Workspace_Access_Token_Expires_At', so the
auditSettingOperation branch that resets it (using Settings.resetValueById) is
never executed; fix this by adding the exact string
'Cloud_Workspace_Access_Token_Expires_At' to the settingsIds array where the
other Cloud_Workspace_* IDs are pushed (so the existing map over settingsIds
will call auditSettingOperation for it), keeping the existing special-case
handling for 'uniqueID' and the Date(0) reset branch intact.In
@apps/meteor/app/api/server/v1/moderation.ts:
- Around line 405-425: The code only deletes the first page of reported messages
because it uses getPaginationItems to set count/offset but then hides reports
for the whole user; fix by retrieving and deleting all reported messages for the
user before hiding reports. Replace the paginated fetch with a full fetch (use
ModerationReports.findReportedMessagesByReportedUserId with offset 0 and count
equal to totalCount or iterate the returned cursor until exhausted) so messages
= await cursor.toArray() contains every reported message for userId, then call
deleteReportedMessages(messages.map(m => m.message), moderator) and finally
ModerationReports.hideMessageReportsByUserId(userId, this.userId,
sanitizedReason, 'DELETE Messages').- Around line 295-319: The current flow paginates raw report rows (cursor from
ModerationReports.findReportedMessagesByReportedUserId) then deduplicates by
report.message._id, which can return fewer unique messages than requested and
misreport count; change the logic to perform deduplication before applying
offset/count: retrieve all matching report rows (or modify
ModerationReports.findReportedMessagesByReportedUserId to return distinct
message-level results), build uniqueMessages by message._id first, then apply
offset/count slicing to uniqueMessages, and ensure the returned count uses
messages.length (uniqueMessages after slicing) while leaving total as the total
unique message count; update usages of cursor, reports, uniqueMessages and the
API.v1.success payload accordingly.
Duplicate comments:
In@apps/meteor/app/api/server/v1/misc.ts:
- Around line 603-613: The 429 schema is unreachable because rate-limit
Meteor.Error thrown inside the try is being normalized to API.v1.failure in the
catch blocks for the method handlers; update the catch logic in the
method.call/:method and method.callAnon/:method handlers to detect the
rate-limit Meteor.Error (check for the Meteor.Error instance and its rate-limit
identifying fields, e.g. error code/string or numeric 429) and preserve it by
either rethrowing it or by returning a response with HTTP status 429 (rather
than the generic 400), and ensure you add the same 429 response mapping to the
method.callAnon/:method responses block so the OpenAPI contract matches the
runtime behavior.- Around line 333-373: The spotlightResponseSchema currently marks user fields
"name" and "statusText" as required which rejects valid spotlight hits; update
the users item schema in spotlightResponseSchema by removing "name" and
"statusText" from the required array (leave only the truly mandatory fields such
as "_id" and "username", and optionally "status" if you want to keep it
required) so optional spotlight fields are not enforced during validation.In
@docs/api-endpoint-migration.md:
- Around line 510-535: Add a clarifying note after the "What augmentation
enables" list stating that the module augmentation via declare module
'@rocket.chat/rest-typings' (and types extracted with
ExtractRoutesFromAPI/typeof myEndpoints) only takes effect for code compiled
within the same TypeScript project/compilation context (so useEndpoint and
api.get typed benefits apply only to consumers built together), and explicitly
call out that independently-compiled packages like packages/ddp-client will not
see these augmentations unless TypeScript project references or equivalent
cross-package type sharing is configured.- Line 454: Update the sentence that claims augmentations apply "across the
entire codebase (SDK, client, tests)" to narrow the scope: state that module
augmentations (when chaining migrated endpoints, storing result, and using
ExtractRoutesFromAPI to augment the Endpoints interface in rest-typings) only
apply to consumers compiled in the same TypeScript project/context (e.g., code
within apps/meteor or packages compiled together) and are not visible to
independently compiled packages like packages/ddp-client in the RocketChat
monorepo that lack project references; adjust the example wording to mention
apps/meteor explicitly as the augmentation declaration location and note the
limitation for independently-built packages.
Nitpick comments:
In@apps/meteor/app/api/server/v1/moderation.ts:
- Around line 24-29: Move the repeated AJV workaround TODO about
IModerationAudit.ts/Date|string out of the implementation and into a single
shared location (e.g., file header comment or a dedicated migration/README
helper) and replace each inline block with a short one-line pointer to that
single note; specifically, consolidate the comment that explains the ts union
causing AJV oneOf failures (mentions IModerationAudit, ts, AJV, and the relaxed
inline schema workaround) and remove the duplicate blocks sprinkled through the
implementation so only a single linked explanation remains.In
@docs/api-endpoint-migration.md:
- Around line 424-426: The fenced code block containing the error message "must
match exactly one schema in oneOf (passingSchemas: 0,1)" needs a language
specifier added to the opening backticks; update the block in the docs to use a
labeled fence (for example changetotext) so the snippet is consistently
highlighted as plain text.</details> <details> <summary>🪄 Autofix (Beta)</summary> Fix all unresolved CodeRabbit comments on this PR: - [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended) - [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes </details> --- <details> <summary>ℹ️ Review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: Organization UI **Review profile**: CHILL **Plan**: Pro **Run ID**: `b477090a-a644-499a-a0a0-94a038249396` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between f5de26e3721a1870579ed3ebee8acd0012f30b8d and d0257b4f4c4c950a3138337cb8efb85c8570032f. </details> <details> <summary>📒 Files selected for processing (9)</summary> * `apps/meteor/app/api/server/definition.ts` * `apps/meteor/app/api/server/v1/import.ts` * `apps/meteor/app/api/server/v1/misc.ts` * `apps/meteor/app/api/server/v1/moderation.ts` * `docs/api-endpoint-migration.md` * `packages/core-typings/src/Ajv.ts` * `packages/http-router/src/Router.spec.ts` * `packages/http-router/src/Router.ts` * `packages/models/src/models/ModerationReports.ts` </details> <details> <summary>🚧 Files skipped from review as they are similar to previous changes (3)</summary> * packages/models/src/models/ModerationReports.ts * packages/http-router/src/Router.ts * packages/http-router/src/Router.spec.ts </details> </details> <details> <summary>📜 Review details</summary> <details> <summary>⏰ 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)</summary> * GitHub Check: 📦 Build Packages * GitHub Check: CodeQL-Build * GitHub Check: CodeQL-Build </details> <details> <summary>🧰 Additional context used</summary> <details> <summary>📓 Path-based instructions (1)</summary> <details> <summary>**/*.{ts,tsx,js}</summary> **📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)** > `**/*.{ts,tsx,js}`: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests > Avoid code comments in the implementation Files: - `apps/meteor/app/api/server/v1/import.ts` - `apps/meteor/app/api/server/v1/moderation.ts` - `packages/core-typings/src/Ajv.ts` - `apps/meteor/app/api/server/v1/misc.ts` - `apps/meteor/app/api/server/definition.ts` </details> </details><details> <summary>🧠 Learnings (18)</summary> <details> <summary>📓 Common learnings</summary> ``` Learnt from: ahmed-n-abdeltwab Repo: RocketChat/Rocket.Chat PR: 38974 File: apps/meteor/app/api/server/v1/im.ts:220-221 Timestamp: 2026-02-24T19:09:09.561Z Learning: In RocketChat/Rocket.Chat OpenAPI migration PRs for apps/meteor/app/api/server/v1 endpoints, maintainers prefer to avoid any logic changes; style-only cleanups (like removing inline comments) may be deferred to follow-ups to keep scope tight. ``` ``` Learnt from: ahmed-n-abdeltwab Repo: RocketChat/Rocket.Chat PR: 39414 File: apps/meteor/app/api/server/v1/rooms.ts:1241-1297 Timestamp: 2026-03-10T08:13:52.153Z Learning: In the RocketChat/Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1/rooms.ts, the pattern `ajv.compile<void>({...})` is intentionally used for the 200 response schema even when the endpoint returns `{ success: true }`. This is an established convention across all migrated endpoints (rooms.leave, rooms.favorite, rooms.delete, rooms.muteUser, rooms.unmuteUser). Do not flag this as a type mismatch during reviews of these migration PRs. ``` ``` Learnt from: ggazzo Repo: RocketChat/Rocket.Chat PR: 35995 File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112 Timestamp: 2026-02-23T17:53:18.785Z Learning: In Rocket.Chat PR reviews, maintain strict scope boundaries—when a PR is focused on a specific endpoint (e.g., rooms.favorite), avoid reviewing or suggesting changes to other endpoints that were incidentally refactored (e.g., rooms.invite) unless explicitly requested by maintainers. ``` </details> <details> <summary>📚 Learning: 2026-02-24T19:09:01.522Z</summary> ``` Learnt from: ahmed-n-abdeltwab Repo: RocketChat/Rocket.Chat PR: 38974 File: apps/meteor/app/api/server/v1/im.ts:220-221 Timestamp: 2026-02-24T19:09:01.522Z Learning: In Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1, avoid introducing logic changes. Only perform scope-tight changes that preserve behavior; style-only cleanups (e.g., removing inline comments) may be deferred to follow-ups to keep the migration PR focused. ``` **Applied to files:** - `apps/meteor/app/api/server/v1/import.ts` - `apps/meteor/app/api/server/v1/moderation.ts` - `apps/meteor/app/api/server/v1/misc.ts` </details> <details> <summary>📚 Learning: 2026-03-10T08:13:52.153Z</summary> ``` Learnt from: ahmed-n-abdeltwab Repo: RocketChat/Rocket.Chat PR: 39414 File: apps/meteor/app/api/server/v1/rooms.ts:1241-1297 Timestamp: 2026-03-10T08:13:52.153Z Learning: In the RocketChat/Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1/rooms.ts, the pattern `ajv.compile<void>({...})` is intentionally used for the 200 response schema even when the endpoint returns `{ success: true }`. This is an established convention across all migrated endpoints (rooms.leave, rooms.favorite, rooms.delete, rooms.muteUser, rooms.unmuteUser). Do not flag this as a type mismatch during reviews of these migration PRs. ``` **Applied to files:** - `apps/meteor/app/api/server/v1/import.ts` - `apps/meteor/app/api/server/v1/moderation.ts` - `packages/core-typings/src/Ajv.ts` - `apps/meteor/app/api/server/v1/misc.ts` - `docs/api-endpoint-migration.md` </details> <details> <summary>📚 Learning: 2026-01-26T18:26:01.279Z</summary> ``` Learnt from: d-gubert Repo: RocketChat/Rocket.Chat PR: 38227 File: apps/meteor/app/api/server/router.ts:44-49 Timestamp: 2026-01-26T18:26:01.279Z Learning: In apps/meteor/app/api/server/router.ts, when retrieving bodyParams and queryParams from the Hono context via c.get(), do not add defensive defaults (e.g., ?? {}). The code should fail fast if these parameters are missing, as endpoint handlers expect them to be present and breaking here helps surface parsing problems rather than hiding them. ``` **Applied to files:** - `apps/meteor/app/api/server/v1/import.ts` - `apps/meteor/app/api/server/v1/misc.ts` - `docs/api-endpoint-migration.md` </details> <details> <summary>📚 Learning: 2026-01-17T01:51:47.764Z</summary> ``` Learnt from: tassoevan Repo: RocketChat/Rocket.Chat PR: 38219 File: packages/core-typings/src/cloud/Announcement.ts:5-6 Timestamp: 2026-01-17T01:51:47.764Z Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected. ``` **Applied to files:** - `apps/meteor/app/api/server/v1/import.ts` - `apps/meteor/app/api/server/v1/moderation.ts` - `packages/core-typings/src/Ajv.ts` - `apps/meteor/app/api/server/v1/misc.ts` - `docs/api-endpoint-migration.md` </details> <details> <summary>📚 Learning: 2026-02-25T20:10:16.987Z</summary> ``` Learnt from: ahmed-n-abdeltwab Repo: RocketChat/Rocket.Chat PR: 38913 File: packages/ddp-client/src/legacy/types/SDKLegacy.ts:34-34 Timestamp: 2026-02-25T20:10:16.987Z Learning: In the RocketChat/Rocket.Chat monorepo, packages/ddp-client and apps/meteor do not use TypeScript project references. Module augmentations in apps/meteor (e.g., declare module 'rocket.chat/rest-typings') are not visible when compiling packages/ddp-client in isolation, which is why legacy SDK methods that depend on OperationResult types for OpenAPI-migrated endpoints must remain commented out. ``` **Applied to files:** - `apps/meteor/app/api/server/v1/import.ts` - `apps/meteor/app/api/server/v1/moderation.ts` - `apps/meteor/app/api/server/v1/misc.ts` - `apps/meteor/app/api/server/definition.ts` - `docs/api-endpoint-migration.md` </details> <details> <summary>📚 Learning: 2026-02-23T17:53:06.802Z</summary> ``` Learnt from: ggazzo Repo: RocketChat/Rocket.Chat PR: 35995 File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112 Timestamp: 2026-02-23T17:53:06.802Z Learning: During PR reviews that touch endpoint files under apps/meteor/app/api/server/v1, enforce strict scope: if a PR targets a specific endpoint (e.g., rooms.favorite), do not propose changes to unrelated endpoints (e.g., rooms.invite) unless maintainers explicitly request them. Focus feedback on the touched endpoint's behavior, API surface, and related tests; avoid broad cross-endpoint changes in the same PR unless requested. ``` **Applied to files:** - `apps/meteor/app/api/server/v1/import.ts` - `apps/meteor/app/api/server/v1/moderation.ts` - `apps/meteor/app/api/server/v1/misc.ts` </details> <details> <summary>📚 Learning: 2026-02-26T19:25:44.063Z</summary> ``` Learnt from: gabriellsh Repo: RocketChat/Rocket.Chat PR: 38778 File: packages/ui-voip/src/providers/useMediaSession.ts:192-192 Timestamp: 2026-02-26T19:25:44.063Z Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules. ``` **Applied to files:** - `apps/meteor/app/api/server/v1/import.ts` - `apps/meteor/app/api/server/v1/moderation.ts` - `packages/core-typings/src/Ajv.ts` - `apps/meteor/app/api/server/v1/misc.ts` - `apps/meteor/app/api/server/definition.ts` </details> <details> <summary>📚 Learning: 2026-02-26T19:25:44.063Z</summary> ``` Learnt from: gabriellsh Repo: RocketChat/Rocket.Chat PR: 38778 File: packages/ui-voip/src/providers/useMediaSession.ts:192-192 Timestamp: 2026-02-26T19:25:44.063Z Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead. ``` **Applied to files:** - `apps/meteor/app/api/server/v1/import.ts` - `apps/meteor/app/api/server/v1/moderation.ts` - `packages/core-typings/src/Ajv.ts` - `apps/meteor/app/api/server/v1/misc.ts` - `apps/meteor/app/api/server/definition.ts` </details> <details> <summary>📚 Learning: 2026-03-03T11:11:48.541Z</summary> ``` Learnt from: ahmed-n-abdeltwab Repo: RocketChat/Rocket.Chat PR: 39230 File: apps/meteor/app/api/server/v1/chat.ts:214-222 Timestamp: 2026-03-03T11:11:48.541Z Learning: In apps/meteor/server/lib/moderation/reportMessage.ts, the reportMessage function validates that description is not empty or whitespace-only with `if (!description.trim())`. When migrating the chat.reportMessage endpoint to OpenAPI, adding minLength validation to the schema preserves this existing behavior. ``` **Applied to files:** - `apps/meteor/app/api/server/v1/moderation.ts` - `apps/meteor/app/api/server/v1/misc.ts` </details> <details> <summary>📚 Learning: 2026-02-24T19:36:55.089Z</summary> ``` Learnt from: juliajforesti Repo: RocketChat/Rocket.Chat PR: 38493 File: apps/meteor/tests/e2e/page-objects/fragments/home-content.ts:60-82 Timestamp: 2026-02-24T19:36:55.089Z Learning: In RocketChat/Rocket.Chat e2e tests (apps/meteor/tests/e2e/page-objects/fragments/home-content.ts), thread message preview listitems do not have aria-roledescription="message", so lastThreadMessagePreview locator cannot be scoped to messageListItems (which filters for aria-roledescription="message"). It should remain scoped to page.getByRole('listitem') or mainMessageList.getByRole('listitem'). ``` **Applied to files:** - `apps/meteor/app/api/server/v1/moderation.ts` - `docs/api-endpoint-migration.md` </details> <details> <summary>📚 Learning: 2026-03-11T16:46:50.707Z</summary> ``` Learnt from: ricardogarim Repo: RocketChat/Rocket.Chat PR: 39535 File: apps/meteor/app/apps/server/bridges/livechat.ts:249-249 Timestamp: 2026-03-11T16:46:50.707Z Learning: In `apps/meteor/app/apps/server/bridges/livechat.ts`, `createVisitor()` intentionally does not propagate `externalIds` to `registerData`. This is by design: the method is deprecated (JSDoc: `deprecated Use createAndReturnVisitor instead. Note: This method does not support externalIds.`) to push callers toward `createAndReturnVisitor()`, which does support `externalIds`. Do not flag the missing `externalIds` field in `createVisitor()` as a bug. ``` **Applied to files:** - `apps/meteor/app/api/server/v1/misc.ts` </details> <details> <summary>📚 Learning: 2025-10-06T20:32:23.658Z</summary> ``` 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/api/server/v1/misc.ts` - `docs/api-endpoint-migration.md` </details> <details> <summary>📚 Learning: 2025-10-16T21:09:51.816Z</summary> ``` Learnt from: cardoso Repo: RocketChat/Rocket.Chat PR: 36942 File: apps/meteor/client/lib/e2ee/keychain.ts:148-156 Timestamp: 2025-10-16T21:09:51.816Z Learning: In the RocketChat/Rocket.Chat repository, only platforms with native crypto.randomUUID() support are targeted, so fallback implementations for crypto.randomUUID() are not required in E2EE or cryptographic code. ``` **Applied to files:** - `apps/meteor/app/api/server/v1/misc.ts` </details> <details> <summary>📚 Learning: 2026-02-24T19:09:09.561Z</summary> ``` Learnt from: ahmed-n-abdeltwab Repo: RocketChat/Rocket.Chat PR: 38974 File: apps/meteor/app/api/server/v1/im.ts:220-221 Timestamp: 2026-02-24T19:09:09.561Z Learning: In RocketChat/Rocket.Chat OpenAPI migration PRs for apps/meteor/app/api/server/v1 endpoints, maintainers prefer to avoid any logic changes; style-only cleanups (like removing inline comments) may be deferred to follow-ups to keep scope tight. ``` **Applied to files:** - `docs/api-endpoint-migration.md` </details> <details> <summary>📚 Learning: 2026-02-23T17:53:18.785Z</summary> ``` Learnt from: ggazzo Repo: RocketChat/Rocket.Chat PR: 35995 File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112 Timestamp: 2026-02-23T17:53:18.785Z Learning: In Rocket.Chat PR reviews, maintain strict scope boundaries—when a PR is focused on a specific endpoint (e.g., rooms.favorite), avoid reviewing or suggesting changes to other endpoints that were incidentally refactored (e.g., rooms.invite) unless explicitly requested by maintainers. ``` **Applied to files:** - `docs/api-endpoint-migration.md` </details> <details> <summary>📚 Learning: 2025-12-10T21:00:54.909Z</summary> ``` Learnt from: KevLehman Repo: RocketChat/Rocket.Chat PR: 37091 File: ee/packages/abac/jest.config.ts:4-7 Timestamp: 2025-12-10T21:00:54.909Z Learning: Rocket.Chat monorepo: Jest testMatch pattern '<rootDir>/src/**/*.spec.(ts|js|mjs)' is valid in this repo and used across multiple packages (e.g., packages/tools, ee/packages/omnichannel-services). Do not flag it as invalid in future reviews. ``` **Applied to files:** - `docs/api-endpoint-migration.md` </details> <details> <summary>📚 Learning: 2026-03-04T14:16:49.202Z</summary> ``` Learnt from: tassoevan Repo: RocketChat/Rocket.Chat PR: 39304 File: packages/ui-contexts/src/ActionManagerContext.ts:26-26 Timestamp: 2026-03-04T14:16:49.202Z Learning: In `packages/ui-contexts/src/ActionManagerContext.ts` (TypeScript, RocketChat/Rocket.Chat), the `disposeView` method in `IActionManager` uses an intentionally explicit union `UiKit.ModalView['id'] | UiKit.BannerView['viewId'] | UiKit.ContextualBarView['id']` to document which view types are accepted, even though all constituents resolve to the same primitive. The inline `// eslint-disable-next-line typescript-eslint/no-duplicate-type-constituents` comment is intentional and should not be flagged or removed. ``` **Applied to files:** - `docs/api-endpoint-migration.md` </details> </details><details> <summary>🪛 markdownlint-cli2 (0.21.0)</summary> <details> <summary>docs/api-endpoint-migration.md</summary> [warning] 424-424: Fenced code blocks should have a language specified (MD040, fenced-code-language) </details> </details> </details> <details> <summary>🔇 Additional comments (6)</summary><blockquote> <details> <summary>packages/core-typings/src/Ajv.ts (1)</summary><blockquote> `3-52`: **LGTM!** The expansion of the `typia.json.schemas` union to include additional types (IBanner, ICalendarEvent, IEmailInbox, IImport, IRole, IRoom, IDirectoryChannelResult, IUser, IDirectoryUserResult, VideoConference, VideoConferenceInstructions, VideoConferenceCapabilities, Cloud-related types, and moderation types) correctly follows the existing pattern. The parenthesized union structure ensures typia generates individual JSON schemas for each constituent type, which will be properly consumed by the ajv registration and OpenAPI spec generation. </blockquote></details> <details> <summary>docs/api-endpoint-migration.md (5)</summary><blockquote> `1-127`: **Clear introduction and well-structured examples.** The "Why" section effectively motivates the migration, and the before/after examples provide excellent context for understanding the pattern change. --- `128-231`: **Comprehensive step-by-step migration guide.** The progression from identifying HTTP methods through creating response schemas is logical and well-documented with clear examples. --- `536-559`: **Clear guidance on handling multiple HTTP methods.** The example effectively shows how to split combined route registrations into separate, explicit method calls with their own validation schemas. --- `560-598`: **Valuable test migration guidance.** The documentation of `errorType` changes and error message format differences will be essential for updating tests during endpoint migrations. --- `599-627`: **Helpful reference section for migration work.** The tracking script and reference file table provide practical resources for developers performing migrations. </blockquote></details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
| settingsIds.push( | ||
| 'Cloud_Service_Agree_PrivacyTerms', | ||
| 'Cloud_Workspace_Id', | ||
| 'Cloud_Workspace_Name', | ||
| 'Cloud_Workspace_Client_Id', | ||
| 'Cloud_Workspace_Client_Secret', | ||
| 'Cloud_Workspace_Client_Secret_Expires_At', | ||
| 'Cloud_Workspace_Registration_Client_Uri', | ||
| 'Cloud_Workspace_PublicKey', | ||
| 'Cloud_Workspace_License', | ||
| 'Cloud_Workspace_Had_Trial', | ||
| 'uniqueID', | ||
| ); | ||
| } | ||
|
|
||
| settingsIds.push('Deployment_FingerPrint_Verified'); | ||
|
|
||
| const auditSettingOperation = updateAuditedByUser({ | ||
| _id: this.userId, | ||
| username: this.user.username ?? '', | ||
| ip: this.requestIp ?? '', | ||
| useragent: this.request.headers.get('user-agent') ?? '', | ||
| }); | ||
|
|
||
| const promises = settingsIds.map((settingId) => { | ||
| if (settingId === 'uniqueID') { | ||
| return auditSettingOperation(Settings.resetValueById, 'uniqueID', process.env.DEPLOYMENT_ID || crypto.randomUUID()); | ||
| } | ||
|
|
||
| if (settingId === 'Cloud_Workspace_Access_Token_Expires_At') { | ||
| return auditSettingOperation(Settings.resetValueById, 'Cloud_Workspace_Access_Token_Expires_At', new Date(0)); | ||
| } |
There was a problem hiding this comment.
Cloud_Workspace_Access_Token_Expires_At never gets reset here.
Lines 837-839 are dead because that setting id is never pushed into settingsIds in Lines 808-820. A new-workspace reset will leave the old access-token expiry timestamp behind.
Suggested fix
settingsIds.push(
'Cloud_Service_Agree_PrivacyTerms',
'Cloud_Workspace_Id',
'Cloud_Workspace_Name',
'Cloud_Workspace_Client_Id',
'Cloud_Workspace_Client_Secret',
+ 'Cloud_Workspace_Access_Token_Expires_At',
'Cloud_Workspace_Client_Secret_Expires_At',
'Cloud_Workspace_Registration_Client_Uri',
'Cloud_Workspace_PublicKey',
'Cloud_Workspace_License',🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/meteor/app/api/server/v1/misc.ts` around lines 808 - 839, The code
pushes a list of setting IDs into settingsIds but never includes
'Cloud_Workspace_Access_Token_Expires_At', so the auditSettingOperation branch
that resets it (using Settings.resetValueById) is never executed; fix this by
adding the exact string 'Cloud_Workspace_Access_Token_Expires_At' to the
settingsIds array where the other Cloud_Workspace_* IDs are pushed (so the
existing map over settingsIds will call auditSettingOperation for it), keeping
the existing special-case handling for 'uniqueID' and the Date(0) reset branch
intact.
| const { cursor, totalCount } = ModerationReports.findReportedMessagesByReportedUserId(userId, escapedSelector, { | ||
| offset, | ||
| count, | ||
| sort, | ||
| }); | ||
|
|
||
| const [reports, total] = await Promise.all([cursor.toArray(), totalCount]); | ||
| const [reports, total] = await Promise.all([cursor.toArray(), totalCount]); | ||
|
|
||
| const uniqueMessages: ReportMessage[] = []; | ||
| const visited = new Set<string>(); | ||
| for (const report of reports) { | ||
| if (visited.has(report.message._id)) { | ||
| continue; | ||
| } | ||
| visited.add(report.message._id); | ||
| uniqueMessages.push(report); | ||
| const uniqueMessages: ReportMessage[] = []; | ||
| const visited = new Set<string>(); | ||
| for (const report of reports) { | ||
| if (visited.has(report.message._id)) { | ||
| continue; | ||
| } | ||
|
|
||
| return API.v1.success({ | ||
| user, | ||
| messages: uniqueMessages, | ||
| count: reports.length, | ||
| total, | ||
| offset, | ||
| }); | ||
| }, | ||
| visited.add(report.message._id); | ||
| uniqueMessages.push(report); | ||
| } | ||
|
|
||
| return API.v1.success({ | ||
| user, | ||
| messages: uniqueMessages, | ||
| count: reports.length, | ||
| total, | ||
| offset, | ||
| }); |
There was a problem hiding this comment.
Paginating before deduping can skip reported messages.
The cursor is paginated on raw report rows first, then duplicates are collapsed by message._id. If one message has several reports, this page can return fewer unique messages than requested, and later unique messages get pushed to later pages; count also reports reports.length, not the returned messages.length.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/meteor/app/api/server/v1/moderation.ts` around lines 295 - 319, The
current flow paginates raw report rows (cursor from
ModerationReports.findReportedMessagesByReportedUserId) then deduplicates by
report.message._id, which can return fewer unique messages than requested and
misreport count; change the logic to perform deduplication before applying
offset/count: retrieve all matching report rows (or modify
ModerationReports.findReportedMessagesByReportedUserId to return distinct
message-level results), build uniqueMessages by message._id first, then apply
offset/count slicing to uniqueMessages, and ensure the returned count uses
messages.length (uniqueMessages after slicing) while leaving total as the total
unique message count; update usages of cursor, reports, uniqueMessages and the
API.v1.success payload accordingly.
| const { count = 50, offset = 0 } = await getPaginationItems(this.queryParams); | ||
|
|
||
| const { cursor, totalCount } = ModerationReports.findReportedMessagesByReportedUserId(userId, '', { | ||
| offset, | ||
| count, | ||
| sort: { ts: -1 }, | ||
| }); | ||
| const { cursor, totalCount } = ModerationReports.findReportedMessagesByReportedUserId(userId, '', { | ||
| offset, | ||
| count, | ||
| sort: { ts: -1 }, | ||
| }); | ||
|
|
||
| const [messages, total] = await Promise.all([cursor.toArray(), totalCount]); | ||
| const [messages, total] = await Promise.all([cursor.toArray(), totalCount]); | ||
|
|
||
| if (total === 0) { | ||
| return API.v1.failure('No reported messages found for this user.'); | ||
| } | ||
| if (total === 0) { | ||
| return API.v1.failure('No reported messages found for this user.'); | ||
| } | ||
|
|
||
| await deleteReportedMessages( | ||
| messages.map((message) => message.message), | ||
| moderator, | ||
| ); | ||
| await deleteReportedMessages( | ||
| messages.map((message) => message.message), | ||
| moderator, | ||
| ); | ||
|
|
||
| await ModerationReports.hideMessageReportsByUserId(userId, this.userId, sanitizedReason, 'DELETE Messages'); | ||
| await ModerationReports.hideMessageReportsByUserId(userId, this.userId, sanitizedReason, 'DELETE Messages'); | ||
|
|
There was a problem hiding this comment.
This bulk delete only processes the first page of reports.
Lines 405-413 fetch at most the default page, but Line 424 hides reports for the whole user. Users with more than one page of reported messages will keep undeleted messages whose reports were already archived.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/meteor/app/api/server/v1/moderation.ts` around lines 405 - 425, The code
only deletes the first page of reported messages because it uses
getPaginationItems to set count/offset but then hides reports for the whole
user; fix by retrieving and deleting all reported messages for the user before
hiding reports. Replace the paginated fetch with a full fetch (use
ModerationReports.findReportedMessagesByReportedUserId with offset 0 and count
equal to totalCount or iterate the returned cursor until exhausted) so messages
= await cursor.toArray() contains every reported message for userId, then call
deleteReportedMessages(messages.map(m => m.message), moderator) and finally
ModerationReports.hideMessageReportsByUserId(userId, this.userId,
sanitizedReason, 'DELETE Messages').
|
nice work 👍 we went from 21% to 34% migrations so far thanks to this |
This pull request refactors several API endpoint implementations to improve validation, error handling, and OpenAPI schema consistency. The main changes involve migrating from legacy route registration to new
API.v1.getandAPI.v1.postmethods, adding explicit response schemas, and updating parameter validation. These updates enhance reliability, ensure stricter contract enforcement, and make API responses easier to document and consume.API Schema and Validation Improvements
API.v1.addRoutecalls to newAPI.v1.getandAPI.v1.postmethods across multiple files, enabling explicit response schemas and improved parameter validation for endpoints such asassets,autotranslate,banners, andcalendar-events. [1] [2] [3] [4]Parameter Handling and Type Improvements
queryandbodyfields instead of legacyvalidateParams, improving clarity and correctness of input handling. [1] [2] [3] [4]Record<string, unknown>instead ofobjectfor response bodies, and ensuring nullable fields are handled correctly. [1] [2] [3]Consistency and Error Handling
{ success: true }and explicit schemas for returned objects or arrays. [1] [2] [3]OpenAPI and Core Typings Integration
IBanner,ICalendarEvent,ISupportedLanguage) into response schemas for better OpenAPI documentation and type safety. [1] [2] [3] [4]Cleanup and Modernization
These changes collectively make the API more robust, easier to maintain, and friendlier for clients and documentation tools.
Proposed changes (including videos or screenshots)
Issue(s)
Steps to test or reproduce
Further comments
Task: ARCH-2050
Summary by CodeRabbit
New Features
Improvements
Documentation
Tests