Skip to content

chore: Convert some apis to openAPI #39265

Merged
ggazzo merged 14 commits intodevelopfrom
chore/api-username
Mar 12, 2026
Merged

chore: Convert some apis to openAPI #39265
ggazzo merged 14 commits intodevelopfrom
chore/api-username

Conversation

@ggazzo
Copy link
Copy Markdown
Member

@ggazzo ggazzo commented Mar 2, 2026

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.get and API.v1.post methods, 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

  • Migrated legacy API.v1.addRoute calls to new API.v1.get and API.v1.post methods across multiple files, enabling explicit response schemas and improved parameter validation for endpoints such as assets, autotranslate, banners, and calendar-events. [1] [2] [3] [4]
  • Added AJV-based response schemas for success and error responses, including type-safe definitions for returned data, and standardized error handling (400, 401, 403) for all affected endpoints. [1] [2] [3] [4] [5]

Parameter Handling and Type Improvements

  • Updated parameter validation to use query and body fields instead of legacy validateParams, improving clarity and correctness of input handling. [1] [2] [3] [4]
  • Refined type checks, such as using Record<string, unknown> instead of object for response bodies, and ensuring nullable fields are handled correctly. [1] [2] [3]

Consistency and Error Handling

  • Standardized response structure for success and error cases, including consistent use of { success: true } and explicit schemas for returned objects or arrays. [1] [2] [3]
  • Improved error handling by checking user permissions and ownership before allowing modifications or deletions, and throwing errors when invalid conditions are detected. [1] [2]

OpenAPI and Core Typings Integration

  • Integrated core typings (e.g., IBanner, ICalendarEvent, ISupportedLanguage) into response schemas for better OpenAPI documentation and type safety. [1] [2] [3] [4]

Cleanup and Modernization

  • Removed redundant code and legacy route registration, consolidating endpoint definitions and improving maintainability. [1] [2] [3] [4]

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

    • Added autotranslate endpoints (translate message, save settings), e2e user key management, and cloud checkout URL.
  • Improvements

    • Migrated many v1 API routes to explicit HTTP methods with schema-driven validation and consistent success/error responses.
    • Directory responses now return optimized user/channel shapes; calendar, email-inbox, settings, moderation, roles, video conference, and import APIs have improved contracts and validations.
    • Error messages now include clearer validation path details.
  • Documentation

    • Added API Endpoint Migration Guide.
  • Tests

    • Updated tests to match revised validation/error messages.

@dionisio-bot
Copy link
Copy Markdown
Contributor

dionisio-bot bot commented Mar 2, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 2, 2026

⚠️ No Changeset found

Latest commit: d0257b4

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 2, 2026

Walkthrough

Migrates 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

Cohort / File(s) Summary
API Type Definition
apps/meteor/app/api/server/definition.ts
Tightened SuccessResult conditional: T extends objectT extends Record<string, unknown> (one-line typing change).
Assets & Banners
apps/meteor/app/api/server/v1/assets.ts, apps/meteor/app/api/server/v1/banners.ts
Replaced addRoute with API.v1.post/get, added AJV request/response schemas, switched to action() handlers, moved validation to body/query, and wired standardized error validators.
Autotranslate & E2E
apps/meteor/app/api/server/v1/autotranslate.ts, apps/meteor/app/api/server/v1/e2e.ts
Added new POST endpoints, AJV request schemas and response maps; consolidated endpoints into endpoint chains and adjusted several 200 response shapes (some removed success requirement); added exported validator types and module augmentation.
Calendar, Cloud, VideoConference
apps/meteor/app/api/server/v1/calendar.ts, .../cloud.ts, .../videoConference.ts
Large refactor to explicit routes with body/query validators and response schemas; handlers moved to action() functions; added many AJV response schemas and refined permission/validation flows.
Email Inbox & Import
apps/meteor/app/api/server/v1/email-inbox.ts, apps/meteor/app/api/server/v1/import.ts
Rewrote routes to use schema-driven validation and explicit HTTP methods; introduced paginated/structured response schemas, standardized error mappings, and replaced inline checks with AJV validators and service calls.
Integrations & Moderation
apps/meteor/app/api/server/v1/integrations.ts, apps/meteor/app/api/server/v1/moderation.ts
Converted many endpoints to method-specific registrations with AJV request/response schemas, added inline compiled response schemas (pagination, reports, success shapes), and replaced validateParams with query/body validators.
Misc, Roles, Settings
apps/meteor/app/api/server/v1/misc.ts, .../roles.ts, .../settings.ts
Added method.call/:method and method.callAnon/:method; introduced extensive AJV schemas for many misc and settings routes; grouped roles routes, augmented REST typings, and added stricter body/query validation and response shapes.
Core typings & Ajv schemas
packages/core-typings/src/Ajv.ts, packages/core-typings/src/IRoom.ts, packages/core-typings/src/IUser.ts
Expanded typia.json.schemas union to include many new types; added IDirectoryChannelResult and IDirectoryUserResult public types.
REST typings
packages/rest-typings/src/v1/directory.ts, .../email-inbox.ts, .../misc.ts
Directory endpoint return type updated to use directory result types; email-inbox IMAP adds optional maxRetries; pw.getPolicy value type widened to allow boolean.
HTTP router & specs
packages/http-router/src/Router.ts, .../Router.spec.ts
Improved response-validation error formatting to include path context and detailed per-error messages; 400 responses now include constructed errorMessage and raw body.
Models
packages/models/src/models/ModerationReports.ts
Added roomIds projection in findMessageReportsGroupedByUser aggregation.
Client components
apps/meteor/client/views/.../UsersTable/UsersTable.tsx, .../UsersTableRow.tsx
Changed user prop types from Serialized<IUser> to Serialized<IDirectoryUserResult> and added import for the new type.
Tests
apps/meteor/tests/end-to-end/api/*
Updated expected error message strings (removed [invalid-params] suffix in several tests; some errorType strings changed to error-invalid-params) and adjusted one 403 test payload to non-empty.
Docs
docs/api-endpoint-migration.md
Added a migration guide documenting steps to convert addRoute → explicit HTTP-method routes with AJV schemas, examples, and testing guidance.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'chore: Convert some apis to openAPI' accurately describes the main objective of the pull request, which involves migrating API endpoints to use OpenAPI-compatible schemas and patterns.
Linked Issues check ✅ Passed The PR is linked to ARCH-2050, which was auto-created to reference the PR itself. The changes implement the objectives stated in the PR description: migrating legacy API routes to new API.v1.get/post patterns with AJV-based validation, response schemas, and OpenAPI compatibility.
Out of Scope Changes check ✅ Passed All changes remain in scope: API endpoint refactoring (assets, autotranslate, banners, calendar, etc.), type definitions (IDirectoryUserResult, IDirectoryChannelResult), validation schema updates, and documentation. Minor updates to test expectations reflect the new error message format.

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


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

❤️ Share

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

@ggazzo ggazzo changed the title Chore/api username chore: convert apis Mar 2, 2026
@ggazzo ggazzo changed the title chore: convert apis chore: Convert apis Mar 2, 2026
@ggazzo ggazzo force-pushed the chore/api-username branch 5 times, most recently from ab8a39c to d91f357 Compare March 3, 2026 01:15
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 70.93%. Comparing base (c987432) to head (d0257b4).
⚠️ Report is 10 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             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     
Flag Coverage Δ
e2e 60.38% <ø> (-0.02%) ⬇️
e2e-api 49.21% <ø> (+1.41%) ⬆️
unit 71.60% <100.00%> (-0.04%) ⬇️

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

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

@ggazzo ggazzo force-pushed the chore/api-username branch from d91f357 to 3b24978 Compare March 3, 2026 03:12
@ggazzo ggazzo changed the base branch from develop to chore/username-api March 3, 2026 03:13
@ggazzo ggazzo force-pushed the chore/api-username branch 8 times, most recently from e57e31d to 344d5fb Compare March 3, 2026 17:21
Base automatically changed from chore/username-api to develop March 3, 2026 20:55
@ggazzo ggazzo force-pushed the chore/api-username branch 6 times, most recently from 5f1c345 to 4a7f5fa Compare March 4, 2026 23:55
@ggazzo ggazzo changed the title chore: Convert apis chore: Convert some apis to openAPI Mar 11, 2026
Copy link
Copy Markdown
Contributor

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

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Nitpick comments (4)
apps/meteor/app/api/server/v1/email-inbox.ts (1)

79-82: Consider simplifying the maxRetries extraction.

Since isEmailInbox validates the body and the EmailInboxProps type already defines maxRetries?: number in imap, 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 for data property.

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) and const 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 supports type='users' filtering via useDirectoryQuery(..., 'users', workspace), which ensures only user results are returned. However, the REST type definition returns a union (IDirectoryUserResult | IDirectoryChannelResult)[] regardless of the type parameter.

Consider updating /v1/directory endpoint typing to support type-narrowed return types, so the return type is IDirectoryUserResult[] when type='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

📥 Commits

Reviewing files that changed from the base of the PR and between b29fb86 and a065bd8.

📒 Files selected for processing (32)
  • apps/meteor/app/api/server/definition.ts
  • apps/meteor/app/api/server/v1/assets.ts
  • apps/meteor/app/api/server/v1/autotranslate.ts
  • apps/meteor/app/api/server/v1/banners.ts
  • apps/meteor/app/api/server/v1/calendar.ts
  • apps/meteor/app/api/server/v1/cloud.ts
  • apps/meteor/app/api/server/v1/e2e.ts
  • apps/meteor/app/api/server/v1/email-inbox.ts
  • apps/meteor/app/api/server/v1/import.ts
  • apps/meteor/app/api/server/v1/integrations.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/app/api/server/v1/moderation.ts
  • apps/meteor/app/api/server/v1/roles.ts
  • apps/meteor/app/api/server/v1/settings.ts
  • apps/meteor/app/api/server/v1/videoConference.ts
  • apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx
  • apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTableRow.tsx
  • apps/meteor/tests/end-to-end/api/banners.ts
  • apps/meteor/tests/end-to-end/api/cloud.ts
  • apps/meteor/tests/end-to-end/api/incoming-integrations.ts
  • apps/meteor/tests/end-to-end/api/livechat/11-email-inbox.ts
  • apps/meteor/tests/end-to-end/api/outgoing-integrations.ts
  • docs/api-endpoint-migration.md
  • packages/core-typings/src/Ajv.ts
  • packages/core-typings/src/IRoom.ts
  • packages/core-typings/src/IUser.ts
  • packages/http-router/src/Router.spec.ts
  • packages/http-router/src/Router.ts
  • packages/models/src/models/ModerationReports.ts
  • packages/rest-typings/src/v1/directory.ts
  • packages/rest-typings/src/v1/email-inbox.ts
  • packages/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.ts
  • packages/rest-typings/src/v1/email-inbox.ts
  • packages/models/src/models/ModerationReports.ts
  • packages/rest-typings/src/v1/misc.ts
  • apps/meteor/app/api/server/definition.ts
  • packages/http-router/src/Router.ts
  • packages/rest-typings/src/v1/directory.ts
  • packages/core-typings/src/IUser.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/app/api/server/v1/videoConference.ts
  • packages/core-typings/src/IRoom.ts
  • apps/meteor/tests/end-to-end/api/outgoing-integrations.ts
  • apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTableRow.tsx
  • apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx
  • apps/meteor/tests/end-to-end/api/incoming-integrations.ts
  • apps/meteor/tests/end-to-end/api/livechat/11-email-inbox.ts
  • apps/meteor/app/api/server/v1/cloud.ts
  • apps/meteor/tests/end-to-end/api/cloud.ts
  • apps/meteor/app/api/server/v1/banners.ts
  • apps/meteor/tests/end-to-end/api/banners.ts
  • apps/meteor/app/api/server/v1/roles.ts
  • apps/meteor/app/api/server/v1/email-inbox.ts
  • apps/meteor/app/api/server/v1/import.ts
  • apps/meteor/app/api/server/v1/assets.ts
  • packages/core-typings/src/Ajv.ts
  • apps/meteor/app/api/server/v1/integrations.ts
  • apps/meteor/app/api/server/v1/calendar.ts
  • apps/meteor/app/api/server/v1/settings.ts
  • apps/meteor/app/api/server/v1/moderation.ts
  • apps/meteor/app/api/server/v1/autotranslate.ts
  • apps/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.ts extension 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.ts
  • packages/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.ts
  • docs/api-endpoint-migration.md
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/app/api/server/v1/videoConference.ts
  • apps/meteor/tests/end-to-end/api/incoming-integrations.ts
  • apps/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.ts
  • apps/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.ts
  • packages/rest-typings/src/v1/email-inbox.ts
  • packages/models/src/models/ModerationReports.ts
  • packages/rest-typings/src/v1/misc.ts
  • apps/meteor/app/api/server/definition.ts
  • packages/http-router/src/Router.ts
  • packages/rest-typings/src/v1/directory.ts
  • packages/core-typings/src/IUser.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/app/api/server/v1/videoConference.ts
  • packages/core-typings/src/IRoom.ts
  • apps/meteor/tests/end-to-end/api/outgoing-integrations.ts
  • apps/meteor/tests/end-to-end/api/incoming-integrations.ts
  • apps/meteor/tests/end-to-end/api/livechat/11-email-inbox.ts
  • apps/meteor/app/api/server/v1/cloud.ts
  • apps/meteor/tests/end-to-end/api/cloud.ts
  • apps/meteor/app/api/server/v1/banners.ts
  • apps/meteor/tests/end-to-end/api/banners.ts
  • apps/meteor/app/api/server/v1/roles.ts
  • apps/meteor/app/api/server/v1/email-inbox.ts
  • apps/meteor/app/api/server/v1/import.ts
  • apps/meteor/app/api/server/v1/assets.ts
  • packages/core-typings/src/Ajv.ts
  • apps/meteor/app/api/server/v1/integrations.ts
  • apps/meteor/app/api/server/v1/calendar.ts
  • apps/meteor/app/api/server/v1/settings.ts
  • apps/meteor/app/api/server/v1/moderation.ts
  • apps/meteor/app/api/server/v1/autotranslate.ts
  • apps/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.ts
  • packages/rest-typings/src/v1/email-inbox.ts
  • packages/models/src/models/ModerationReports.ts
  • packages/rest-typings/src/v1/misc.ts
  • apps/meteor/app/api/server/definition.ts
  • packages/http-router/src/Router.ts
  • packages/rest-typings/src/v1/directory.ts
  • packages/core-typings/src/IUser.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/app/api/server/v1/videoConference.ts
  • packages/core-typings/src/IRoom.ts
  • apps/meteor/tests/end-to-end/api/outgoing-integrations.ts
  • apps/meteor/tests/end-to-end/api/incoming-integrations.ts
  • apps/meteor/tests/end-to-end/api/livechat/11-email-inbox.ts
  • apps/meteor/app/api/server/v1/cloud.ts
  • apps/meteor/tests/end-to-end/api/cloud.ts
  • apps/meteor/app/api/server/v1/banners.ts
  • apps/meteor/tests/end-to-end/api/banners.ts
  • apps/meteor/app/api/server/v1/roles.ts
  • apps/meteor/app/api/server/v1/email-inbox.ts
  • apps/meteor/app/api/server/v1/import.ts
  • apps/meteor/app/api/server/v1/assets.ts
  • packages/core-typings/src/Ajv.ts
  • apps/meteor/app/api/server/v1/integrations.ts
  • apps/meteor/app/api/server/v1/calendar.ts
  • apps/meteor/app/api/server/v1/settings.ts
  • apps/meteor/app/api/server/v1/moderation.ts
  • apps/meteor/app/api/server/v1/autotranslate.ts
  • apps/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.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/tests/end-to-end/api/incoming-integrations.ts
  • apps/meteor/tests/end-to-end/api/livechat/11-email-inbox.ts
  • apps/meteor/app/api/server/v1/email-inbox.ts
  • apps/meteor/app/api/server/v1/moderation.ts
  • apps/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.ts
  • apps/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.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/tests/end-to-end/api/incoming-integrations.ts
  • apps/meteor/app/api/server/v1/cloud.ts
  • apps/meteor/tests/end-to-end/api/cloud.ts
  • apps/meteor/app/api/server/v1/banners.ts
  • apps/meteor/tests/end-to-end/api/banners.ts
  • apps/meteor/app/api/server/v1/email-inbox.ts
  • packages/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.ts
  • packages/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.ts
  • packages/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.ts
  • docs/api-endpoint-migration.md
  • packages/rest-typings/src/v1/directory.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTableRow.tsx
  • apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx
  • apps/meteor/app/api/server/v1/cloud.ts
  • apps/meteor/app/api/server/v1/roles.ts
  • apps/meteor/app/api/server/v1/email-inbox.ts
  • apps/meteor/app/api/server/v1/import.ts
  • apps/meteor/app/api/server/v1/assets.ts
  • apps/meteor/app/api/server/v1/integrations.ts
  • apps/meteor/app/api/server/v1/settings.ts
  • apps/meteor/app/api/server/v1/moderation.ts
  • apps/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.md
  • packages/rest-typings/src/v1/directory.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/app/api/server/v1/videoConference.ts
  • apps/meteor/app/api/server/v1/cloud.ts
  • apps/meteor/app/api/server/v1/banners.ts
  • apps/meteor/app/api/server/v1/roles.ts
  • apps/meteor/app/api/server/v1/email-inbox.ts
  • apps/meteor/app/api/server/v1/import.ts
  • apps/meteor/app/api/server/v1/assets.ts
  • packages/core-typings/src/Ajv.ts
  • apps/meteor/app/api/server/v1/integrations.ts
  • apps/meteor/app/api/server/v1/moderation.ts
  • apps/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.ts
  • packages/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.ts
  • apps/meteor/app/api/server/v1/videoConference.ts
  • apps/meteor/app/api/server/v1/cloud.ts
  • apps/meteor/app/api/server/v1/banners.ts
  • apps/meteor/app/api/server/v1/roles.ts
  • apps/meteor/app/api/server/v1/email-inbox.ts
  • apps/meteor/app/api/server/v1/import.ts
  • apps/meteor/app/api/server/v1/assets.ts
  • apps/meteor/app/api/server/v1/integrations.ts
  • apps/meteor/app/api/server/v1/calendar.ts
  • apps/meteor/app/api/server/v1/settings.ts
  • apps/meteor/app/api/server/v1/moderation.ts
  • apps/meteor/app/api/server/v1/autotranslate.ts
  • apps/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.ts
  • apps/meteor/app/api/server/v1/videoConference.ts
  • apps/meteor/app/api/server/v1/cloud.ts
  • apps/meteor/app/api/server/v1/banners.ts
  • apps/meteor/app/api/server/v1/roles.ts
  • apps/meteor/app/api/server/v1/email-inbox.ts
  • apps/meteor/app/api/server/v1/import.ts
  • apps/meteor/app/api/server/v1/assets.ts
  • apps/meteor/app/api/server/v1/integrations.ts
  • apps/meteor/app/api/server/v1/calendar.ts
  • apps/meteor/app/api/server/v1/settings.ts
  • apps/meteor/app/api/server/v1/moderation.ts
  • apps/meteor/app/api/server/v1/autotranslate.ts
  • apps/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.ts
  • apps/meteor/tests/end-to-end/api/livechat/11-email-inbox.ts
  • apps/meteor/tests/end-to-end/api/cloud.ts
  • apps/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.ts
  • apps/meteor/tests/end-to-end/api/livechat/11-email-inbox.ts
  • apps/meteor/tests/end-to-end/api/cloud.ts
  • apps/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.ts
  • apps/meteor/tests/end-to-end/api/cloud.ts
  • apps/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.ts
  • apps/meteor/tests/end-to-end/api/cloud.ts
  • apps/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.ts
  • apps/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.ts
  • apps/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.ts
  • 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 **/*.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.ts
  • apps/meteor/tests/end-to-end/api/livechat/11-email-inbox.ts
  • apps/meteor/tests/end-to-end/api/cloud.ts
  • apps/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.ts
  • apps/meteor/tests/end-to-end/api/cloud.ts
  • apps/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.ts
  • apps/meteor/tests/end-to-end/api/cloud.ts
  • apps/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.ts
  • apps/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)

Comment on lines +88 to 99
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 });
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

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.

Suggested change
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.

Comment on lines +121 to +137
200: ajv.compile<IEmailInbox | null>({
oneOf: [
{
allOf: [
{ $ref: '#/components/schemas/IEmailInbox' },
{
type: 'object',
properties: {
success: { type: 'boolean', enum: [true] },
},
required: ['success'],
},
],
},
{ type: 'null' },
],
}),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

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

Comment on lines +333 to +373
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,
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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.

Comment on lines +603 to +612
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,
}),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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.

Comment on lines +311 to +341
.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,
}),
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

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

Comment on lines +137 to 169
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,
});
},
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

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

Comment on lines +209 to +239
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();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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.

Comment on lines +408 to +409
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).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

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.

KevLehman
KevLehman previously approved these changes Mar 11, 2026
cardoso
cardoso previously approved these changes Mar 11, 2026
@ggazzo ggazzo dismissed stale reviews from cardoso, julio-rocketchat, and KevLehman via f5de26e March 11, 2026 18:58
@ggazzo ggazzo force-pushed the chore/api-username branch from a065bd8 to f5de26e Compare March 11, 2026 18:58
KevLehman
KevLehman previously approved these changes Mar 11, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (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., text or plaintext) 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.md around 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 opening totext or

linting/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 reportedEmails instead. 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

📥 Commits

Reviewing files that changed from the base of the PR and between a065bd8 and f5de26e.

📒 Files selected for processing (9)
  • 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
🚧 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.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • packages/core-typings/src/Ajv.ts
  • apps/meteor/app/api/server/v1/import.ts
  • apps/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.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/app/api/server/v1/import.ts
  • apps/meteor/app/api/server/v1/moderation.ts
  • docs/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.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • packages/core-typings/src/Ajv.ts
  • apps/meteor/app/api/server/v1/import.ts
  • apps/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.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • packages/core-typings/src/Ajv.ts
  • apps/meteor/app/api/server/v1/import.ts
  • apps/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.ts
  • apps/meteor/app/api/server/v1/import.ts
  • apps/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.ts
  • packages/core-typings/src/Ajv.ts
  • apps/meteor/app/api/server/v1/import.ts
  • apps/meteor/app/api/server/v1/moderation.ts
  • docs/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.ts
  • apps/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.ts
  • packages/core-typings/src/Ajv.ts
  • apps/meteor/app/api/server/v1/moderation.ts
  • docs/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.ts
  • apps/meteor/app/api/server/v1/import.ts
  • docs/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.ts
  • docs/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.ts
  • apps/meteor/app/api/server/v1/import.ts
  • apps/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 object to extends 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 to success().

docs/api-endpoint-migration.md (1)

454-455: Narrow the type-coverage claim around Endpoints augmentation.

The phrase "entire codebase (SDK, client, tests)" overstates augmentation visibility. Module augmentations declared in apps/meteor are not visible when packages/ddp-client is 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 of required.

name and statusText are optional on the selected IUser shape, 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.Error thrown at lines 643-646 is caught by the broad catch at line 649, which always returns API.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 meResponseSchema with additionalProperties: true is appropriate for the flexible user data structure, and the migration to API.v1.get with explicit response schemas follows the new pattern correctly.


395-469: LGTM!

The directory endpoint migration correctly uses oneOf with $ref for the union type IDirectoryUserResult | 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, VideoConference types, Cloud types, IImport) enables $ref usage 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, and operationResponseSchema correctly include the success field and follow the established pattern.


73-136: LGTM!

The endpoint migrations for uploadImportFile, downloadPublicImportFile, and startImport correctly use body validators and response schemas with proper error mappings.

apps/meteor/app/api/server/v1/moderation.ts (5)

24-60: LGTM!

The paginatedReportsResponseSchema correctly documents the Date | string issue with a TODO comment (as recommended in the migration guide) and uses a relaxed inline schema. The required fields match the projection from findMessageReportsGroupedByUser (context snippet 1).


62-96: LGTM!

The paginatedUserReportsResponseSchema required fields (reportedUser, ts, count) match the projection from findUserReports aggregation pipeline (context snippet 3).


269-321: LGTM!

The message deduplication logic using a Set to track visited message IDs is a clean approach to avoid returning duplicate messages in the response.


591-621: LGTM!

The moderation.reportUser endpoint correctly validates the reported user exists before creating the report, and passes the appropriate user fields to createWithDescriptionAndUser matching the expected reportedBy type from IModerationReport.


249-265: ⚠️ Potential issue | 🟠 Major

Type cast masks structural mismatch between actual and declared response schema.

findUserReports returns Pick<UserReport, '_id' | 'reportedUser' | 'ts'> & { count: number } (only 4 fields), but the response is cast to IModerationAudit[] 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.

Comment on lines +178 to 201
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);
},
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

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.

ggazzo added 5 commits March 11, 2026 17:25
- 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.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (4)
docs/api-endpoint-migration.md (2)

510-535: 🛠️ Refactor suggestion | 🟠 Major

Clarify 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 like ddp-client will 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 | 🟠 Major

Narrow 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 | 🟠 Major

The 429 contract is still unreachable in both method-call handlers.

The rate-limit Meteor.Error is thrown inside the try, but both catch blocks immediately normalize it to API.v1.failure(...), so callers still get the generic 400 payload instead of 429. Once that case is preserved, method.callAnon/:method also 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 | 🟠 Major

Keep optional spotlight fields out of required.

Line 351 makes name and statusText mandatory, 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.md around 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
change totext) 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 change totext) 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 -->

Comment on lines +808 to 839
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));
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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.

Comment on lines +295 to +319
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,
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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.

Comment on lines +405 to 425
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');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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').

@ahmed-n-abdeltwab
Copy link
Copy Markdown
Contributor

nice work 👍 we went from 21% to 34% migrations so far thanks to this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants