Skip to content

chore: convert endpoints do openApi#39553

Open
ggazzo wants to merge 38 commits intodevelopfrom
chore/apis
Open

chore: convert endpoints do openApi#39553
ggazzo wants to merge 38 commits intodevelopfrom
chore/apis

Conversation

@ggazzo
Copy link
Copy Markdown
Member

@ggazzo ggazzo commented Mar 12, 2026

This pull request introduces significant improvements to the API endpoints in the Rocket.Chat codebase, focusing on enhanced type safety, input/output validation, and response consistency. The changes primarily center around the adoption of AJV-based schema validation for request and response payloads, the refactoring of several API routes to use a more declarative style, and improvements to type usage throughout the API layer.

The most important changes are:

API Schema Validation and Type Safety

  • Refactored multiple API endpoints (such as /commands, /chat.react, /chat.reportMessage, /info, /docs/json) to use AJV schemas for validating request bodies, query parameters, and responses, ensuring stricter API contracts and improved error handling. [1] [2] [3] [4] [5] [6] [7] [8] [9]

  • Introduced explicit type usage for API responses, such as IMeApiUser for user info and typed schemas for command endpoints, reducing ambiguity and improving maintainability. [1] [2] [3] [4]

API Endpoint Refactoring

  • Replaced legacy addRoute definitions with a new, more declarative .get and .post chaining style for endpoints, consolidating validation, authentication, and response schemas in a single place. [1] [2] [3] [4] [5] [6] [7] [8] [9]

  • Removed redundant manual input checks in favor of schema-based validation, resulting in cleaner and more robust endpoint implementations. [1] [2] [3]

Consistency and Error Handling

  • Standardized API success and error responses across endpoints, including the use of validateBadRequestErrorResponse, validateUnauthorizedErrorResponse, and validateForbiddenErrorResponse for consistent error reporting. [1] [2] [3] [4]

Minor Bug Fixes

  • Fixed a potential bug in the channels unread count calculation by ensuring a default date is provided if subscription.ls is undefined.

Minor Improvements

  • Improved method overloading and type inference in ApiClass.ts for the forbidden method, clarifying its return type and usage.

These changes collectively modernize the API layer, improve reliability, and make the codebase easier to maintain and extend.

Task: ARCH-2063

Summary by CodeRabbit

  • Bug Fixes

    • Fixed unread-count and read-state handling when subscription timestamps are missing
    • Ensured integrations are persisted and verified after creation
    • Livechat room filtering accepts boolean open values
    • Made user-data synchronization and subscription mapping more tolerant of missing fields
  • New Features

    • Stricter request/response validation across many API endpoints for more predictable responses
    • Standardized /me and push response shapes for clearer client contracts
    • Added repository analysis and migration helper scripts; updated migration guidance documentation

@dionisio-bot
Copy link
Copy Markdown
Contributor

dionisio-bot bot commented Mar 12, 2026

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

  • This PR is missing the 'stat: QA assured' label
  • This PR is targeting the wrong base branch. It should target 8.4.0, but it targets 8.3.0

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 12, 2026

⚠️ No Changeset found

Latest commit: 40ff9cc

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 12, 2026

Note

Reviews paused

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

Use the following commands to manage reviews:

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

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Migrates many endpoints from legacy addRoute patterns to explicit API.get/post handlers with AJV request/response schemas, tightens TypeScript and JSON schemas (me, integration, subscription, push, etc.), adds repository analysis CLI scripts, and applies defensive runtime fixes across client/server code and tests.

Changes

Cohort / File(s) Summary
Default / OpenAPI routes
apps/meteor/app/api/server/default/info.ts, apps/meteor/app/api/server/default/openApi.ts
Switched to API.default.get(...), added AJV-compiled response schemas, moved inline handlers to standalone action() functions, and attached response validation.
V1 API endpoints (schema & wiring)
apps/meteor/app/api/server/v1/.../commands.ts, .../custom-user-status.ts, .../emoji-custom.ts, .../invites.ts, .../mailer.ts, .../misc.ts, .../moderation.ts, .../push.ts, .../stats.ts, .../subscriptions.ts, .../channels.ts
Replaced addRoute with API.v1.get/post(...), introduced AJV request/response schemas (including standardized error schemas), tightened response shapes, and moved handlers into action() functions; includes refined input validation and some control-flow defensive fixes.
/v1/me and getUserInfo
apps/meteor/app/api/server/helpers/getUserInfo.ts, apps/meteor/app/api/server/v1/misc.ts
Changed getUserInfo return type to IMeApiUser, improved service typings, and wired /v1/me to use compiled MeApiSuccessResponse schema, removing permissive object casts.
Core typings updates
packages/core-typings/src/IMeApiUser.ts, IIntegration.ts, ISubscription.ts, IVideoConference.ts, Ajv.ts, index.ts
Added IMeApiUser and service types; made integration token/script and subscription ls/lr optional; removed Nullable helper; expanded typia schema union.
REST typings & me response
packages/rest-typings/src/v1/me.ts, .../me/meSuccessResponse.ts, packages/rest-typings/src/index.ts
Introduced MeApiSuccessResponse type and JSON schema, updated /v1/me endpoint typing to use it, and re-exported new types from package index.
Ajv runtime import change
packages/rest-typings/src/v1/Ajv.ts
Switched Ajv import to ajv/dist/2020 for this package's Ajv instance.
Integrations server changes
apps/meteor/app/integrations/server/methods/incoming/addIncomingIntegration.ts, .../updateIncomingIntegration.ts, .../lib/triggerHandler.ts
After insert, fetch and return persisted integration (throw on missing); make $set updates conditional for optional fields; made IntegrationData.token optional in type.
Livechat & client defensive fixes
apps/meteor/app/livechat/imports/server/rest/rooms.ts, apps/meteor/client/lib/chats/readStateManager.ts, apps/meteor/client/lib/userData.ts, apps/meteor/client/lib/utils/mapSubscriptionFromApi.ts
Defensive parsing for boolean/string open, optional chaining and fallbacks for subscription timestamps, safer /v1/me consumption and merging, and conditional ls/lr mapping to Dates.
Authentication startup logging/fixes
apps/meteor/app/authentication/server/startup/index.js
Return removeEmpty(user), refine inactiveReason and username suggestion logic, and add logging around user insertion and re-fetch.
Tests updated
apps/meteor/tests/end-to-end/api/commands.ts, apps/meteor/tests/end-to-end/api/rooms.ts, apps/meteor/tests/end-to-end/apps/slash-command-test-simple.ts
Adjusted e2e assertions to reflect AJV error messages and payload changes; grouped a test with setup/teardown.
Migration tooling scripts
scripts/list-unmigrated-api-endpoints.mjs, scripts/analyze-weak-types.mjs, scripts/list-weak-response-schemas.mjs
Added three CLI scripts to locate legacy addRoute endpoints, detect weak TypeScript/schema patterns, and enumerate permissive response schemas; support JSON output and flags.
Docs
docs/api-endpoint-migration.md
Updated guidance for nullable types, documented known pitfalls for mapped utility types, and added documentation for the new analysis scripts and workflow.
Small/low-risk edits
apps/meteor/app/integrations/server/..., packages/rest-typings/src/v1/push.ts, apps/meteor/app/api/server/ApiClass.ts
Minor signature/typing tweaks (push validators, API.forbidden overloads) and small behavioural/type loosenings across integration types.

Sequence Diagram(s)

(none)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Suggested labels

type: chore

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 64.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'chore: convert endpoints do openApi' is partially related but contains a grammatical error and is vague about scope. Consider revising to 'chore: migrate API endpoints to OpenAPI-driven validation' to be more specific and grammatically correct.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR successfully implements the core objectives from ARCH-2063: replacing manual validation with ajv schemas, adding response validation schemas, and improving type consistency.
Out of Scope Changes check ✅ Passed Changes are within scope: API validation migration, type improvements (IMeApiUser), bug fixes (channels date handling, subscription date optionality), and documentation updates align with ARCH-2063 objectives.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 12, 2026

Codecov Report

❌ Patch coverage is 54.05405% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.56%. Comparing base (9e3eb78) to head (40ff9cc).
⚠️ Report is 9 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #39553      +/-   ##
===========================================
- Coverage    70.58%   70.56%   -0.03%     
===========================================
  Files         3256     3257       +1     
  Lines       115778   115803      +25     
  Branches     21047    21131      +84     
===========================================
- Hits         81723    81714       -9     
- Misses       31994    32027      +33     
- Partials      2061     2062       +1     
Flag Coverage Δ
e2e 60.45% <48.38%> (+0.01%) ⬆️
e2e-api 48.14% <ø> (+0.02%) ⬆️
unit 71.08% <57.14%> (-0.06%) ⬇️

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/apis branch 3 times, most recently from 901177f to 6430325 Compare March 12, 2026 05:10
@ggazzo ggazzo force-pushed the chore/apis branch 9 times, most recently from 26e0171 to 542782d Compare March 20, 2026 03:17
@rc-layne
Copy link
Copy Markdown

rc-layne bot commented Mar 20, 2026

Layne — scan passed

No security issues found on latest push.

@ggazzo ggazzo added this to the 8.3.0 milestone Mar 20, 2026
@ggazzo ggazzo marked this pull request as ready for review March 20, 2026 04:55
@ggazzo ggazzo requested review from a team as code owners March 20, 2026 04:55
@ggazzo
Copy link
Copy Markdown
Member Author

ggazzo commented Mar 20, 2026

/jira ARCH-1464

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.

12 issues found across 40 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="scripts/analyze-weak-types.mjs">

<violation number="1" location="scripts/analyze-weak-types.mjs:46">
P2: `SCHEMA_WEAK_PATTERNS` is declared but never used, so array schemas without `items` are never detected.</violation>
</file>

<file name="apps/meteor/app/api/server/v1/subscriptions.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/subscriptions.ts:26">
P2: `subscriptions.get` response schema incorrectly validates `remove` items as `ISubscription`, but runtime returns only deletion markers (`_id`, `_deletedAt`).</violation>
</file>

<file name="apps/meteor/app/api/server/v1/custom-user-status.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/custom-user-status.ts:164">
P1: Omitting `statusType` on update now clears it to `''` instead of leaving it unchanged.</violation>
</file>

<file name="apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts">

<violation number="1" location="apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts:179">
P1: Truthy-gating these fields prevents clearing `avatar`, `emoji`, or `alias` to empty strings; use presence checks instead of value truthiness.</violation>
</file>

<file name="scripts/list-weak-response-schemas.mjs">

<violation number="1" location="scripts/list-weak-response-schemas.mjs:16">
P2: Using `URL.pathname` directly can break file scanning on encoded filesystem paths.</violation>

<violation number="2" location="scripts/list-weak-response-schemas.mjs:93">
P2: `bare-object` matching is too broad and flags valid multiline object schemas as weak.</violation>
</file>

<file name="apps/meteor/app/api/server/v1/misc.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/misc.ts:348">
P2: `statusText` is optional on users, so requiring it in the spotlight response schema can reject valid responses.</violation>
</file>

<file name="apps/meteor/app/api/server/v1/channels.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/channels.ts:643">
P1: Using `new Date(0)` counts all historical messages since 1970 as unread for new subscriptions. Fall back to `subscription.ts` to count only messages since the user joined.</violation>
</file>

<file name="apps/meteor/app/api/server/v1/moderation.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/moderation.ts:159">
P2: `createdAt` is validated as `string`, but this endpoint returns `IUser.createdAt` as a `Date`, causing response-schema validation to fail.</violation>
</file>

<file name="apps/meteor/client/lib/userData.ts">

<violation number="1" location="apps/meteor/client/lib/userData.ts:130">
P2: Do not default `email2fa.changedAt` to `new Date()` when the API omits it; this writes a fabricated "changed now" timestamp into user state.

(Based on your team's feedback about avoiding unsafe type assumptions and validating values before coercion.) [FEEDBACK_USED]</violation>
</file>

<file name="apps/meteor/app/api/server/v1/invites.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/invites.ts:63">
P2: `sendInvitationEmail` response schema was loosened with `additionalProperties: true`; this weakens response validation and can hide accidental extra fields.</violation>
</file>

<file name="apps/meteor/app/api/server/v1/mailer.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/mailer.ts:33">
P2: Add a 403 response schema for the permission check on `mailer` so forbidden responses are documented and validated.</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: 10

♻️ Duplicate comments (1)
apps/meteor/app/api/server/v1/stats.ts (1)

14-21: ⚠️ Potential issue | 🟠 Major

statistics still skips the IStats contract.

Line 14 only uses IStats as a generic; the schema itself accepts any object with success: true. This endpoint does not have the fields projection problem from statistics.list, so the actual stats shape can still be enforced here instead of leaving the response effectively untyped.

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

In `@apps/meteor/app/api/server/v1/stats.ts` around lines 14 - 21, The response
schema statisticsResponseSchema currently only enforces success: true and thus
ignores the IStats shape; update the Ajv schema used in statisticsResponseSchema
(or replace it) to fully describe the IStats structure (all expected properties
and types) and set additionalProperties: false (or explicitly include any
allowed extra fields) so compile<IStats>(...) truly enforces the IStats
contract; locate statisticsResponseSchema in stats.ts and expand the properties
object to match IStats (or generate the schema from the TypeScript type) and
then recompile with ajv.compile<IStats>.
🧹 Nitpick comments (4)
apps/meteor/tests/end-to-end/api/rooms.ts (1)

2381-2382: Drop the new inline wait comment.

Please keep the intent in code instead of an implementation comment.

✂️ Suggested cleanup
-				// need to wait for the name update finish
 				await sleep(300);

As per coding guidelines "Avoid code comments in the implementation".

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

In `@apps/meteor/tests/end-to-end/api/rooms.ts` around lines 2381 - 2382, Remove
the inline comment and express the intent by replacing the comment + await
sleep(300) with a clearly named helper call (e.g., await waitForNameUpdate()),
implement that helper to encapsulate the waiting strategy (for now it can call
sleep(300) or, better, poll the name update condition) and keep the existing
sleep function name (sleep) only as the underlying primitive; update any
references in the test to call waitForNameUpdate() instead of using an
implementation comment before sleep.
scripts/list-unmigrated-api-endpoints.mjs (1)

30-45: Count verbs or label this output as “registrations.”

A single addRoute() can still expose multiple handlers, but scan() emits one record per path. That makes the Total and endpoints output registration counts, not endpoint counts, so mixed-method routes understate the remaining migration work.

Also applies to: 81-89

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

In `@scripts/list-unmigrated-api-endpoints.mjs` around lines 30 - 45, The scan()
function currently emits one record per path which undercounts multi-method
handlers; modify scan() to either count verbs per registration or explicitly
label records as "registrations": for each match in scan() (using the existing
regex and extractPaths(match[2])), parse or extract the handler verbs for that
addRoute invocation and include them in the results entries (e.g., add a verbs:
[..] array or a registrations: true flag) so the output reflects handler
multiplicity; also update the downstream aggregation logic that computes totals
(the code that processes results into endpoints/Total around the later block
that iterates over results) to sum verb counts when producing endpoint totals or
to treat the output as registration counts when the records are labeled,
ensuring the final "Total" and endpoints output are accurate and consistent.
apps/meteor/app/api/server/v1/custom-user-status.ts (1)

189-209: Missing body schema for custom-user-status.delete endpoint.

The endpoint accesses this.bodyParams.customUserStatusId (line 200) but no body validator is defined in the route options. This allows arbitrary body payloads without AJV validation, relying on the manual check at lines 201-203 instead of schema enforcement.

Consider adding a body schema for consistency with the other migrated endpoints:

♻️ Proposed fix
+const isCustomUserStatusDeleteProps = ajv.compile<{ customUserStatusId: string }>({
+	type: 'object',
+	properties: {
+		customUserStatusId: { type: 'string' },
+	},
+	required: ['customUserStatusId'],
+	additionalProperties: false,
+});
+
 const customUserStatusDeleteResponseSchema = ajv.compile<void>({
 	type: 'object',
 	properties: {
 		success: { type: 'boolean', enum: [true] },
 	},
 	required: ['success'],
 	additionalProperties: false,
 });
 
 API.v1.post(
 	'custom-user-status.delete',
 	{
 		authRequired: true,
+		body: isCustomUserStatusDeleteProps,
 		response: {
 		},
 	},
 	async function action() {
 		const { customUserStatusId } = this.bodyParams;
-		if (!customUserStatusId) {
-			return API.v1.failure('The "customUserStatusId" params is required!');
-		}
 
 		await deleteCustomUserStatus(this.userId, customUserStatusId);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/app/api/server/v1/custom-user-status.ts` around lines 189 - 209,
Add a request body schema to the custom-user-status.delete route so AJV
validates this.bodyParams.customUserStatusId instead of relying on a manual
runtime check: define a request schema (e.g.,
customUserStatusDeleteRequestSchema) that requires a non-empty
customUserStatusId (string) and add it to the route options under the body key
of the API.v1.post call for 'custom-user-status.delete'; keep the existing
runtime call to deleteCustomUserStatus(this.userId, customUserStatusId)
unchanged but remove the manual presence check if you prefer strict schema
validation only.
apps/meteor/client/lib/userData.ts (1)

126-133: Inconsistent date fallback: new Date() vs new Date(0) pattern.

Lines 109-110 use new Date(0) (epoch) as a sentinel for missing dates, but line 130 uses new Date() (current time) for missing email2fa.changedAt. This inconsistency could cause confusion — a missing changedAt would appear as "just now" rather than "unknown/never set."

Consider using new Date(0) for consistency:

🔧 Suggested fix
 ...(email2fa
   ? {
       email2fa: {
         ...email2fa,
-        changedAt: email2fa.changedAt ? new Date(email2fa.changedAt) : new Date(),
+        changedAt: email2fa.changedAt ? new Date(email2fa.changedAt) : new Date(0),
       },
     }
   : {}),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/lib/userData.ts` around lines 126 - 133, The email2fa
object construction is using new Date() as a fallback for email2fa.changedAt
which is inconsistent with other places that use new Date(0) as a sentinel;
update the fallback in the email2fa branch so changedAt uses new Date(0) when
missing (i.e., replace new Date() with new Date(0)) to match the existing epoch
sentinel behavior and ensure uniform "unknown/never set" semantics across the
code that reads changedAt.
🤖 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/emoji-custom.ts`:
- Around line 27-38: The response schema emojiCustomAllResponseSchema currently
sets emojis: { type: 'array' } which doesn't validate array items; update the
schema passed to ajv.compile so the emojis property includes an items schema
(either items: { $ref: '<IEmojiCustom ref>' } if IEmojiCustom is registered with
AJV, or a concrete object schema matching IEmojiCustom) and keep
required/additionalProperties rules; ensure the updated shape still includes
success/count/offset/total and passes AJV compilation in the
emojiCustomAllResponseSchema declaration.

In `@apps/meteor/app/api/server/v1/integrations.ts`:
- Around line 36-38: The Typia schema generation currently only registers
IIntegration, but integrations.ts references IIncomingIntegration and
IOutgoingIntegration; open packages/core-typings/src/Ajv.ts and update the
typia.json.schemas(...) tuple to explicitly import and include
IIncomingIntegration and IOutgoingIntegration (following the pattern used for
IDirectoryChannelResult and IDirectoryUserResult) so those concrete refs are
emitted, or alternatively change the refs in integrations.ts to point to the
existing IIntegration schema name; ensure imports and the typia.json.schemas
call include the two constituent types (IIncomingIntegration,
IOutgoingIntegration) alongside IIntegration.

In `@apps/meteor/app/api/server/v1/push.ts`:
- Around line 235-306: The new GET routes 'push.get' and 'push.info' were added
but not included in the extracted route type, so update the module augmentation
that defines PushEndpoints to include these two routes with their expected
request/response shapes; locate the augmentation that declares PushEndpoints
(the same place that currently exposes 'push.token' and 'push.test') and add
entries for 'push.get' and 'push.info' matching the handlers (use the
pushGetResponseSchema shape for 'push.get' and pushInfoResponseSchema shape for
'push.info', and mark both as authRequired GET endpoints) so typed consumers see
the new routes.

In `@apps/meteor/app/api/server/v1/stats.ts`:
- Around line 98-117: The route API.v1.post handler for 'statistics.telemetry'
accepts an unvalidated body (this.bodyParams) and blindly casts/uses it in
function action; add a proper request body schema to the route options (e.g.,
statisticsTelemetryRequestSchema) that requires a params array of objects with
an eventName string and optional params object, enforce it in the route
definition alongside the existing response schemas, and update action to rely on
the validated shape (or defensively check each event contains eventName before
calling telemetryEvent) so telemetryEvent.call is never invoked with undefined
eventName.

In `@apps/meteor/app/api/server/v1/subscriptions.ts`:
- Around line 19-31: subscriptionsGetResponseSchema currently declares remove
items as full ISubscription docs but the TypeScript type expects tombstones
(Pick<ISubscription, '_id'> & {_deletedAt: Date}); update the schema for the
remove array inside subscriptionsGetResponseSchema so its items are an object
with only the tombstone shape (e.g. properties: { _id: { type: 'string' },
_deletedAt: { type: 'string', format: 'date-time' } } and required:
['_id','_deletedAt']) instead of referencing
'#/components/schemas/ISubscription', so Ajv validation matches the TypeScript
type.

In `@apps/meteor/app/authentication/server/startup/index.js`:
- Around line 214-218: Remove the raw console.log dumps that print full signup
payloads (the two console.log calls around beforeCreateUserCallback.run) and
replace them with either no logging or a redacted logger that only records safe
identifiers (e.g., user._id, user.emailHash or user.username, and a note that
callbacks ran) so sensitive fields (password hashes, OAuth tokens, emails in
plain text, approval state) are never written; update the code referencing
beforeCreateUserCallback, options, and user to use the redaction helper or
remove the logs, and apply the same change to the other occurrences mentioned
(the similar console.log uses at the other indicated locations).

In
`@apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts`:
- Around line 179-181: The current spread checks like ...(integration.avatar &&
{ avatar: integration.avatar }) use truthiness and prevent explicit clears
(e.g., avatar: ''), so change those guards to test for undefined/property
presence instead (e.g., use Object.prototype.hasOwnProperty.call(integration,
'avatar') or integration.avatar !== undefined) for avatar, emoji, alias and
script in the update logic (the spread object construction where
integration.avatar/emoji/alias/script are conditionally added); this preserves
omitted fields as no-ops but allows explicit empty-string clears to overwrite
stored values.

In `@scripts/analyze-weak-types.mjs`:
- Around line 45-58: The scan never runs the array pattern from
SCHEMA_WEAK_PATTERNS because only findWeakSchemaBlocks() is invoked; update the
schema-only scan to also execute the array check by either extending
findWeakSchemaBlocks() to apply all SCHEMA_WEAK_PATTERNS (including the array
rule) or adding and calling a dedicated matcher (e.g.,
findWeakSchemaArrayMatches or applyPatternMatches) that runs the second pattern;
ensure the main flow that handles the --schema-only flag calls the new/updated
function so the "{ type: 'array' } (no items)" case is reported.

In `@scripts/list-weak-response-schemas.mjs`:
- Around line 81-95: The 'bare-object' rule in WEAK_PATTERNS currently only
checks the current line in its test(line, context) and thus flags multi-line
schemas where "properties:" or "$ref"/combiners appear on subsequent lines;
update the test in the 'bare-object' entry to perform a lookahead using the
provided context (e.g., inspect subsequent lines/tokens from context for a small
window like the next 5-10 non-empty lines or until indentation/closing token)
and return false if any of properties, $ref, allOf, oneOf, or anyOf are found in
that lookahead; keep the original current-line checks but rely on this
multi-line scan to avoid false positives for standard multi-line object schemas.
- Around line 41-64: The chained-route regex is too broad and matches unrelated
calls like settings.get; update the third pattern in routePatterns inside
extractEndpoints to only match method calls that are part of router chains (e.g.
API.v1, variables ending with "Router"/"router", or common app/router names) by
changing the regex to require a router-like identifier before the dot (for
example using a non-capturing group like
(?:(?:API\.v1|\w*Router|\w*router|\bapp|\broutes))\.(get|post|put|delete)\(\s*['"`]([^'"`]+)['"`])
and adjust the match indexing logic in extractEndpoints accordingly so name
comes from match[2] and method from match[1].

---

Duplicate comments:
In `@apps/meteor/app/api/server/v1/stats.ts`:
- Around line 14-21: The response schema statisticsResponseSchema currently only
enforces success: true and thus ignores the IStats shape; update the Ajv schema
used in statisticsResponseSchema (or replace it) to fully describe the IStats
structure (all expected properties and types) and set additionalProperties:
false (or explicitly include any allowed extra fields) so compile<IStats>(...)
truly enforces the IStats contract; locate statisticsResponseSchema in stats.ts
and expand the properties object to match IStats (or generate the schema from
the TypeScript type) and then recompile with ajv.compile<IStats>.

---

Nitpick comments:
In `@apps/meteor/app/api/server/v1/custom-user-status.ts`:
- Around line 189-209: Add a request body schema to the
custom-user-status.delete route so AJV validates
this.bodyParams.customUserStatusId instead of relying on a manual runtime check:
define a request schema (e.g., customUserStatusDeleteRequestSchema) that
requires a non-empty customUserStatusId (string) and add it to the route options
under the body key of the API.v1.post call for 'custom-user-status.delete'; keep
the existing runtime call to deleteCustomUserStatus(this.userId,
customUserStatusId) unchanged but remove the manual presence check if you prefer
strict schema validation only.

In `@apps/meteor/client/lib/userData.ts`:
- Around line 126-133: The email2fa object construction is using new Date() as a
fallback for email2fa.changedAt which is inconsistent with other places that use
new Date(0) as a sentinel; update the fallback in the email2fa branch so
changedAt uses new Date(0) when missing (i.e., replace new Date() with new
Date(0)) to match the existing epoch sentinel behavior and ensure uniform
"unknown/never set" semantics across the code that reads changedAt.

In `@apps/meteor/tests/end-to-end/api/rooms.ts`:
- Around line 2381-2382: Remove the inline comment and express the intent by
replacing the comment + await sleep(300) with a clearly named helper call (e.g.,
await waitForNameUpdate()), implement that helper to encapsulate the waiting
strategy (for now it can call sleep(300) or, better, poll the name update
condition) and keep the existing sleep function name (sleep) only as the
underlying primitive; update any references in the test to call
waitForNameUpdate() instead of using an implementation comment before sleep.

In `@scripts/list-unmigrated-api-endpoints.mjs`:
- Around line 30-45: The scan() function currently emits one record per path
which undercounts multi-method handlers; modify scan() to either count verbs per
registration or explicitly label records as "registrations": for each match in
scan() (using the existing regex and extractPaths(match[2])), parse or extract
the handler verbs for that addRoute invocation and include them in the results
entries (e.g., add a verbs: [..] array or a registrations: true flag) so the
output reflects handler multiplicity; also update the downstream aggregation
logic that computes totals (the code that processes results into endpoints/Total
around the later block that iterates over results) to sum verb counts when
producing endpoint totals or to treat the output as registration counts when the
records are labeled, ensuring the final "Total" and endpoints output are
accurate and consistent.
🪄 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: 64fd18d3-3d8b-4604-8dfd-ffb7e49aa940

📥 Commits

Reviewing files that changed from the base of the PR and between 61d3d9a and 542782d.

📒 Files selected for processing (40)
  • apps/meteor/app/api/server/default/info.ts
  • apps/meteor/app/api/server/default/openApi.ts
  • apps/meteor/app/api/server/helpers/getUserInfo.ts
  • apps/meteor/app/api/server/v1/channels.ts
  • apps/meteor/app/api/server/v1/commands.ts
  • apps/meteor/app/api/server/v1/custom-user-status.ts
  • apps/meteor/app/api/server/v1/emoji-custom.ts
  • apps/meteor/app/api/server/v1/integrations.ts
  • apps/meteor/app/api/server/v1/invites.ts
  • apps/meteor/app/api/server/v1/mailer.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/app/api/server/v1/moderation.ts
  • apps/meteor/app/api/server/v1/push.ts
  • apps/meteor/app/api/server/v1/stats.ts
  • apps/meteor/app/api/server/v1/subscriptions.ts
  • apps/meteor/app/authentication/server/startup/index.js
  • apps/meteor/app/integrations/server/lib/triggerHandler.ts
  • apps/meteor/app/integrations/server/methods/incoming/addIncomingIntegration.ts
  • apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts
  • apps/meteor/app/livechat/imports/server/rest/rooms.ts
  • apps/meteor/client/lib/chats/readStateManager.ts
  • apps/meteor/client/lib/userData.ts
  • apps/meteor/client/lib/utils/mapSubscriptionFromApi.ts
  • apps/meteor/tests/end-to-end/api/commands.ts
  • apps/meteor/tests/end-to-end/api/rooms.ts
  • apps/meteor/tests/end-to-end/apps/slash-command-test-simple.ts
  • docs/api-endpoint-migration.md
  • packages/core-typings/src/Ajv.ts
  • packages/core-typings/src/IIntegration.ts
  • packages/core-typings/src/IMeApiUser.ts
  • packages/core-typings/src/ISubscription.ts
  • packages/core-typings/src/IVideoConference.ts
  • packages/core-typings/src/index.ts
  • packages/rest-typings/src/index.ts
  • packages/rest-typings/src/v1/Ajv.ts
  • packages/rest-typings/src/v1/me.ts
  • packages/rest-typings/src/v1/me/meSuccessResponse.ts
  • scripts/analyze-weak-types.mjs
  • scripts/list-unmigrated-api-endpoints.mjs
  • scripts/list-weak-response-schemas.mjs

Comment on lines +36 to +38
integration: {
oneOf: [{ $ref: '#/components/schemas/IIncomingIntegration' }, { $ref: '#/components/schemas/IOutgoingIntegration' }],
},
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\nRefs introduced in apps/meteor/app/api/server/v1/integrations.ts:\n'
rg -n '\$ref: .*/I(Incoming|Outgoing)Integration' apps/meteor/app/api/server/v1/integrations.ts

printf '\nAjv registrations/imports in packages/core-typings/src/Ajv.ts:\n'
rg -n 'IIncomingIntegration|IOutgoingIntegration|IIntegrationHistory|IIntegration' packages/core-typings/src/Ajv.ts

printf '\nConcrete integration type definitions:\n'
rg -n 'export interface IIncomingIntegration|export interface IOutgoingIntegration|export type IIntegration' packages/core-typings/src/IIntegration.ts

Repository: RocketChat/Rocket.Chat

Length of output: 1005


🏁 Script executed:

# Check if Typia auto-generates schemas for the concrete integration types
rg -A 20 'createTypiaFormatter' packages/core-typings/src/Ajv.ts | head -40

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check how schemas are generated/registered in Typia
rg -n 'Typia\|schema\|addFormats\|new Ajv' packages/core-typings/src/Ajv.ts | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Verify if IIncomingIntegration or IOutgoingIntegration appear anywhere in Ajv.ts
cat packages/core-typings/src/Ajv.ts

Repository: RocketChat/Rocket.Chat

Length of output: 2179


🏁 Script executed:

# Check how the integration schemas are used in the handlers
rg -B 5 -A 10 'oneOf.*IIncomingIntegration' apps/meteor/app/api/server/v1/integrations.ts | head -60

Repository: RocketChat/Rocket.Chat

Length of output: 1529


🏁 Script executed:

# Check if there's any ajv.compile or schema resolution happening with these response schemas
rg -n 'response.*schema\|ajv\.compile.*integration\|validateResponse' apps/meteor/app/api/server/v1/integrations.ts | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check if IIncomingIntegration or IOutgoingIntegration might be registered elsewhere in the codebase
fd -t f 'Ajv.ts|.*integrations.*\.ts' --exec rg -l 'IIncomingIntegration|IOutgoingIntegration' {} \;

Repository: RocketChat/Rocket.Chat

Length of output: 113


🏁 Script executed:

# Check if there's a schema generation output or build artifact that shows generated schema names
find . -name '*schema*' -o -name '*typia*' | grep -E '\.(json|d\.ts|schema)$' | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 119


🏁 Script executed:

# Look at how the schemas object is used - check if it's imported into integrations.ts
rg -n 'import.*schemas\|from.*Ajv' apps/meteor/app/api/server/v1/integrations.ts

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check if ajv instance is configured with external schemas/definitions
rg -B 10 -A 10 'new Ajv\|ajv\.addSchema' apps/meteor/app/api/server/v1/integrations.ts | head -40

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Search for how the ajv instance is created and if schemas are added to it
rg -rn 'export.*ajv.*=|const ajv.*=' apps/meteor/app/api/server/ | grep -v node_modules

Repository: RocketChat/Rocket.Chat

Length of output: 734


🏁 Script executed:

# Find where ajv instance is created and exported
rg -rn 'export.*const.*ajv|export.*let.*ajv' apps/meteor/app/api/server/ --type ts

Repository: RocketChat/Rocket.Chat

Length of output: 543


🏁 Script executed:

# Look for ajv initialization in the API setup files
rg -B 5 -A 15 'const.*ajv.*=.*new Ajv|export.*ajv.*new Ajv' apps/meteor/app/api/server/ --type ts

Repository: RocketChat/Rocket.Chat

Length of output: 16693


🏁 Script executed:

# Check the main API file structure
ls -la apps/meteor/app/api/server/

Repository: RocketChat/Rocket.Chat

Length of output: 1020


🏁 Script executed:

# Look for where schemas from core-typings are used in API
rg -n 'from.*core-typings.*schemas\|schemas\..*from' apps/meteor/app/api/server/ --type ts | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check the ajv.ts file to see how ajv is created and if schemas are registered
cat apps/meteor/app/api/server/ajv.ts

Repository: RocketChat/Rocket.Chat

Length of output: 480


🏁 Script executed:

# Check if ApiClass.ts sets up schemas or adds them to ajv
rg -n 'schemas\|addSchema\|IIncomingIntegration\|IOutgoingIntegration' apps/meteor/app/api/server/ApiClass.ts | head -30

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check the api.ts file to see the overall setup
cat apps/meteor/app/api/server/api.ts

Repository: RocketChat/Rocket.Chat

Length of output: 3831


🏁 Script executed:

# Check if there's a build output or generated schemas file
find . -name '*.json' -path '*schemas*' -o -name '*typia*' | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Look for Typia documentation or check if it auto-generates schemas for union constituents
# First, let's check what's imported from core-typings in ajv.ts to understand what schemas object contains
rg -A 50 'export const schemas' packages/core-typings/src/Ajv.ts

Repository: RocketChat/Rocket.Chat

Length of output: 740


🏁 Script executed:

# Check if the integration types are mentioned anywhere in Typia schema generation
rg -n 'IIncomingIntegration\|IOutgoingIntegration' packages/core-typings/src/ --type ts

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Let's check what schemas are actually generated by looking at the compiled output
# First find where the schemas are used or generated
rg -n 'schemas\.components' apps/meteor/app/api/server/ --type ts

Repository: RocketChat/Rocket.Chat

Length of output: 324


🏁 Script executed:

# Try to understand what the Typia-generated schemas object contains
# Let's look for any test or documentation about the generated schemas
rg -n 'components.schemas\|IIncomingIntegration\|IOutgoingIntegration' . --type json | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check if there's a way to see what schemas Typia actually generates for union types
# Let's search for how other union types are handled in the codebase
rg -B 5 -A 5 'oneOf.*\$ref' apps/meteor/app/api/server/v1/ --type ts | head -80

Repository: RocketChat/Rocket.Chat

Length of output: 5160


🏁 Script executed:

# Check Typia version and documentation
cat package.json | grep -A 2 -B 2 'typia'

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Let's verify that IDirectoryUserResult and IDirectoryChannelResult are in the Ajv schemas list
rg -n 'IDirectoryUserResult\|IDirectoryChannelResult' packages/core-typings/src/Ajv.ts

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Now check the complete integrations.ts file to see the exact context at those lines
sed -n '30,45p' apps/meteor/app/api/server/v1/integrations.ts
sed -n '145,165p' apps/meteor/app/api/server/v1/integrations.ts
sed -n '280,300p' apps/meteor/app/api/server/v1/integrations.ts

Repository: RocketChat/Rocket.Chat

Length of output: 1948


🏁 Script executed:

# Check if there's any dynamic schema generation or if Typia documentation indicates union constituent schemas are auto-generated
rg -n 'Typia\|@typia' packages/core-typings/ --type ts --type json | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check what's passed to Typia schema generation - look for complete list
rg -B 5 'IRoom.*\|.*IDirectoryChannelResult\|IUser.*\|.*IDirectoryUserResult' packages/core-typings/src/Ajv.ts

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check if both union components are listed explicitly in Ajv.ts
grep -n 'IIncomingIntegration\|IOutgoingIntegration\|IIntegration' packages/core-typings/src/Ajv.ts

Repository: RocketChat/Rocket.Chat

Length of output: 238


🏁 Script executed:

# Look for IDirectoryUserResult and IDirectoryChannelResult in Ajv.ts to compare pattern
grep -n 'IDirectoryUserResult\|IDirectoryChannelResult\|IRoom\|IUser' packages/core-typings/src/Ajv.ts | head -10

Repository: RocketChat/Rocket.Chat

Length of output: 283


🏁 Script executed:

# Try to find if there's test output or error logs showing schema resolution failures
find . -name '*.test.*' -o -name '*.spec.*' | xargs grep -l 'integrations\|IIncomingIntegration\|IOutgoingIntegration' 2>/dev/null | head -5

Repository: RocketChat/Rocket.Chat

Length of output: 203


🏁 Script executed:

# Check what IDirectoryChannelResult and IDirectoryUserResult are - are they separate types or derived?
rg -n 'export.*IDirectoryChannelResult\|export.*IDirectoryUserResult' packages/core-typings/src/

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Now let's check what IIncomingIntegration and IOutgoingIntegration are in IIntegration.ts
head -80 packages/core-typings/src/IIntegration.ts

Repository: RocketChat/Rocket.Chat

Length of output: 1929


🏁 Script executed:

# Let's verify by checking if Typia generates schemas for all types passed to it, or if union constituents need explicit inclusion
# Check if there are any similar patterns where only the union is passed, not constituents
rg -B 3 -A 3 '^\s*\|\s*I[A-Z]\w+.*\|' packages/core-typings/src/Ajv.ts | head -100

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Key question: are IDirectoryChannelResult and IDirectoryUserResult actually separate classes/types, or are they somehow generated from IRoom/IUser?
rg -n 'IDirectoryChannelResult\|IDirectoryUserResult' packages/core-typings/src/IRoom.ts

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check if they're defined in IRoom.ts or elsewhere
rg -n 'export.*IDirectoryChannelResult\|export.*IDirectoryUserResult' packages/core-typings/src/

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Now the critical question: Does Typia auto-generate nested/constituent schemas, or does this require explicit inclusion?
# Let's check if there's any error in test runs or if these refs actually work
rg -n 'IIncomingIntegration\|IOutgoingIntegration' apps/meteor/tests/ --type ts

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check for any known issues or TODOs about this
rg -n 'TODO\|FIXME\|BUG' apps/meteor/app/api/server/v1/integrations.ts | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Let's check the Typia documentation or see if there's a way to verify whether constituent schemas are generated
# First, look for any schema generation output or test that verifies schemas
find . -type f -name '*.json' | xargs grep -l 'IIncomingIntegration\|IOutgoingIntegration' 2>/dev/null | head -5

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Let's verify by checking if there are any similar patterns in the codebase where a union type's constituent refs are used
# Search for all oneOf patterns to see what the convention is
rg -n 'oneOf.*\$ref' apps/meteor/app/api/server/v1/ --type ts | wc -l
rg -n 'oneOf.*\$ref' apps/meteor/app/api/server/v1/ --type ts

Repository: RocketChat/Rocket.Chat

Length of output: 1045


🏁 Script executed:

# Check the core-typings package to see if IIncomingIntegration/IOutgoingIntegration are exported
rg -n '^export' packages/core-typings/src/IIntegration.ts

Repository: RocketChat/Rocket.Chat

Length of output: 569


🏁 Script executed:

# Let me verify the exact difference by comparing the two patterns
# Check what's in IRoom.ts for IDirectoryChannelResult
grep -A 5 'IDirectoryChannelResult' packages/core-typings/src/IRoom.ts | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 159


🏁 Script executed:

# Check if the naming pattern matters - does Typia generate schemas for both the union AND its constituents?
# Let's look at what schemas.components.schemas actually contains by checking where it's used
rg -B 2 -A 10 'schemas.components.schemas' apps/meteor/app/api/server/default/openApi.ts | head -30

Repository: RocketChat/Rocket.Chat

Length of output: 394


🏁 Script executed:

# The critical test: search for where IDirectoryUserResult and IDirectoryChannelResult are defined - are they separate exported types?
fd IRoom.ts -x cat {} | grep -n 'export.*IDirectoryChannelResult\|export.*IDirectoryUserResult'

Repository: RocketChat/Rocket.Chat

Length of output: 112


🏁 Script executed:

# Perfect! Now let's confirm IDirectoryUserResult is also a separate exported type like IDirectoryChannelResult
grep -n 'export.*IDirectoryUserResult' packages/core-typings/src/IUser.ts

Repository: RocketChat/Rocket.Chat

Length of output: 110


🏁 Script executed:

# Now the key comparison: verify both patterns are exported, but only one set is in Ajv.ts
echo "=== Types in Ajv.ts Typia generation ===" 
grep -n 'IIntegration\|IDirectory' packages/core-typings/src/Ajv.ts

echo -e "\n=== Types exported from source files ===" 
echo "From IIntegration.ts:"
grep '^export.*I\(Incoming\|Outgoing\)Integration' packages/core-typings/src/IIntegration.ts
echo "From IRoom.ts:"
grep '^export.*IDirectoryChannelResult' packages/core-typings/src/IRoom.ts
echo "From IUser.ts:"
grep '^export.*IDirectoryUserResult' packages/core-typings/src/IUser.ts

Repository: RocketChat/Rocket.Chat

Length of output: 852


Add IIncomingIntegration and IOutgoingIntegration to Typia schema generation in packages/core-typings/src/Ajv.ts.

Lines 37, 153, and 288 in integrations.ts reference $ref: '#/components/schemas/IIncomingIntegration' and IOutgoingIntegration, but these types are not included in the Typia schema generation tuple. Only the union type IIntegration is passed to typia.json.schemas(). Import and add both constituent types explicitly (following the pattern used for IDirectoryChannelResult and IDirectoryUserResult), or change the refs to use the registered IIntegration schema name.

🤖 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 36 - 38, The
Typia schema generation currently only registers IIntegration, but
integrations.ts references IIncomingIntegration and IOutgoingIntegration; open
packages/core-typings/src/Ajv.ts and update the typia.json.schemas(...) tuple to
explicitly import and include IIncomingIntegration and IOutgoingIntegration
(following the pattern used for IDirectoryChannelResult and
IDirectoryUserResult) so those concrete refs are emitted, or alternatively
change the refs in integrations.ts to point to the existing IIntegration schema
name; ensure imports and the typia.json.schemas call include the two constituent
types (IIncomingIntegration, IOutgoingIntegration) alongside IIntegration.

Comment on lines +19 to 31
const subscriptionsGetResponseSchema = ajv.compile<{
update: ISubscription[];
remove: (Pick<ISubscription, '_id'> & { _deletedAt: Date })[];
}>({
type: 'object',
properties: { success: { type: 'boolean', enum: [true] } },
properties: {
update: { type: 'array', items: { $ref: '#/components/schemas/ISubscription' } },
remove: { type: 'array', items: { $ref: '#/components/schemas/ISubscription' } },
success: { type: 'boolean', enum: [true] },
},
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

remove is validated as the wrong shape.

The TypeScript type says remove contains tombstones (_id + _deletedAt), but the schema now references full ISubscription documents. As soon as subscriptions.get returns a real removal entry, response validation will reject it.

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

In `@apps/meteor/app/api/server/v1/subscriptions.ts` around lines 19 - 31,
subscriptionsGetResponseSchema currently declares remove items as full
ISubscription docs but the TypeScript type expects tombstones
(Pick<ISubscription, '_id'> & {_deletedAt: Date}); update the schema for the
remove array inside subscriptionsGetResponseSchema so its items are an object
with only the tombstone shape (e.g. properties: { _id: { type: 'string' },
_deletedAt: { type: 'string', format: 'date-time' } } and required:
['_id','_deletedAt']) instead of referencing
'#/components/schemas/ISubscription', so Ajv validation matches the TypeScript
type.

ggazzo and others added 4 commits March 23, 2026 14:39
…sages

The migrated endpoints were using forbidden('error-not-allowed') as a
type workaround, but this changed the error response from 'unauthorized'
to 'error-not-allowed', breaking existing tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
API.v1.forbidden() without arguments returns 'unauthorized' for
backward compatibility. The test was expecting the old 'Not allowed'
message.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
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.

2 issues found across 7 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

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


<file name="apps/meteor/app/api/server/v1/im.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/im.ts:313">
P2: `dm.setTopic` can return `topic: null` even though the declared 200 response schema only allows a string.</violation>
</file>

<file name="apps/meteor/app/api/server/v1/commands.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/commands.ts:125">
P2: When apps are not loaded, this branch now returns HTTP 200 instead of an “incomplete, retry later” status, which can make clients treat a partial command list as complete.</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

@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 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

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


<file name="apps/meteor/app/api/server/v1/rooms.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/rooms.ts:630">
P1: Validate that `startingFromId` belongs to the requested room before including it in the response to prevent cross-room file metadata exposure.</violation>
</file>

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

@julio-rocketchat
Copy link
Copy Markdown
Member

/layne exception-approve LAYNE-cf5728a8c5ee4985 LAYNE-1f1d959f7c1f4dbd reason: Unrelated changes to the PR that are already being tracked elsewhere (I'll also ensure Layne is configured to diff-only)

@rc-layne
Copy link
Copy Markdown

rc-layne bot commented Mar 24, 2026

✅ Exception recorded for LAYNE-cf5728a8c5ee4985, LAYNE-1f1d959f7c1f4dbd by @julio-rocketchat: "Unrelated changes to the PR that are already being tracked elsewhere (I'll also ensure Layne is configured to diff-only)". Re-running scan...

@ggazzo ggazzo modified the milestones: 8.3.0, 8.4.0 Mar 24, 2026

return API.default.success(makeOpenAPIResponse(getTypedRoutes(API.api.typedRoutes, { withUndocumented })));
authRequired: false,
query: isOpenAPIJSONEndpoint,
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.

I see isOpenAPIJSONEndpoint is using ajv instead of ajvQuery to compile the schema in packages/rest-typings/src/default/index.ts Is that okay or we should change it?

const { messageId, description } = this.bodyParams;
if (!messageId) {
return API.v1.failure('The required "messageId" param is missing.');
throw new Meteor.Error('error-param-required', 'The required "messageId" param is missing.');
Copy link
Copy Markdown
Contributor

@nazabucciarelli nazabucciarelli Mar 26, 2026

Choose a reason for hiding this comment

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

I thought we wanted to do the opposite, I mean turning throw new Meteor.Error... into API.v1.failure

total: 0,
success: true as const,
},
202,
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.

looks like we are returning 202 status code but we don't have such response schema

}>({
type: 'object',
properties: {
command: { type: 'string' },
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.

what do you think about adding minLength: 1 to command and roomId?

const isCommandsPreviewGetProps = ajv.compile<{ command: string; params?: string; roomId: string }>({
type: 'object',
properties: {
command: { type: 'string' },
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.

same here with minLength: 1

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.

Also I think we should use ajvQuery rather than ajv

query: isPushGetProps,
response: {
200: pushGetResponseSchema,
401: validateUnauthorizedErrorResponse,
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.

the response schema for 400 is missing here

const statisticsListResponseSchema = ajv.compile<{ statistics: IStats[]; count: number; offset: number; total: number }>({
type: 'object',
properties: {
statistics: { type: 'array' },
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.

Suggested change
statistics: { type: 'array' },
statistics: { type: 'array', items: { $ref: '#/components/schemas/IStats' } },

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.

And we would need to add it in Ajv.ts typia schemas

if (!oldest) {
return API.v1.failure('Body parameter "oldest" is required.');
}
if (!latest) {
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.

I guess we can get rid of these latest and oldest checks for existence, since they are required in the isRoomsCleanHistoryProps schema

response: {
200: ajv.compile<void | { missing: string[] }>({
type: 'object',
properties: { success: { type: 'boolean', enum: [true] } },
Copy link
Copy Markdown
Contributor

@nazabucciarelli nazabucciarelli Mar 31, 2026

Choose a reason for hiding this comment

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

should we add missing: { type: 'array', items: { type: 'string' } } to properties? (as I see, missing is returned in line 1017) and additionalProperties: false

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants