Conversation
|
Looks like this PR is not ready to merge, because of the following issues:
Please fix the issues and try again If you have any trouble, please check the PR guidelines |
|
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughMigrates 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
Sequence Diagram(s)(none) Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Suggested labels
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ 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
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
901177f to
6430325
Compare
26e0171 to
542782d
Compare
|
✅ Layne — scan passed No security issues found on latest push. |
|
/jira ARCH-1464 |
There was a problem hiding this comment.
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.
apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 10
♻️ Duplicate comments (1)
apps/meteor/app/api/server/v1/stats.ts (1)
14-21:⚠️ Potential issue | 🟠 Major
statisticsstill skips theIStatscontract.Line 14 only uses
IStatsas a generic; the schema itself accepts any object withsuccess: true. This endpoint does not have thefieldsprojection problem fromstatistics.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, butscan()emits one record per path. That makes theTotalandendpointsoutput 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 forcustom-user-status.deleteendpoint.The endpoint accesses
this.bodyParams.customUserStatusId(line 200) but nobodyvalidator 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()vsnew Date(0)pattern.Lines 109-110 use
new Date(0)(epoch) as a sentinel for missing dates, but line 130 usesnew Date()(current time) for missingemail2fa.changedAt. This inconsistency could cause confusion — a missingchangedAtwould 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
📒 Files selected for processing (40)
apps/meteor/app/api/server/default/info.tsapps/meteor/app/api/server/default/openApi.tsapps/meteor/app/api/server/helpers/getUserInfo.tsapps/meteor/app/api/server/v1/channels.tsapps/meteor/app/api/server/v1/commands.tsapps/meteor/app/api/server/v1/custom-user-status.tsapps/meteor/app/api/server/v1/emoji-custom.tsapps/meteor/app/api/server/v1/integrations.tsapps/meteor/app/api/server/v1/invites.tsapps/meteor/app/api/server/v1/mailer.tsapps/meteor/app/api/server/v1/misc.tsapps/meteor/app/api/server/v1/moderation.tsapps/meteor/app/api/server/v1/push.tsapps/meteor/app/api/server/v1/stats.tsapps/meteor/app/api/server/v1/subscriptions.tsapps/meteor/app/authentication/server/startup/index.jsapps/meteor/app/integrations/server/lib/triggerHandler.tsapps/meteor/app/integrations/server/methods/incoming/addIncomingIntegration.tsapps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.tsapps/meteor/app/livechat/imports/server/rest/rooms.tsapps/meteor/client/lib/chats/readStateManager.tsapps/meteor/client/lib/userData.tsapps/meteor/client/lib/utils/mapSubscriptionFromApi.tsapps/meteor/tests/end-to-end/api/commands.tsapps/meteor/tests/end-to-end/api/rooms.tsapps/meteor/tests/end-to-end/apps/slash-command-test-simple.tsdocs/api-endpoint-migration.mdpackages/core-typings/src/Ajv.tspackages/core-typings/src/IIntegration.tspackages/core-typings/src/IMeApiUser.tspackages/core-typings/src/ISubscription.tspackages/core-typings/src/IVideoConference.tspackages/core-typings/src/index.tspackages/rest-typings/src/index.tspackages/rest-typings/src/v1/Ajv.tspackages/rest-typings/src/v1/me.tspackages/rest-typings/src/v1/me/meSuccessResponse.tsscripts/analyze-weak-types.mjsscripts/list-unmigrated-api-endpoints.mjsscripts/list-weak-response-schemas.mjs
| integration: { | ||
| oneOf: [{ $ref: '#/components/schemas/IIncomingIntegration' }, { $ref: '#/components/schemas/IOutgoingIntegration' }], | ||
| }, |
There was a problem hiding this comment.
🧩 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.tsRepository: 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 -40Repository: 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 -20Repository: 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.tsRepository: 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 -60Repository: 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 -20Repository: 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 -20Repository: 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.tsRepository: 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 -40Repository: 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_modulesRepository: 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 tsRepository: 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 tsRepository: 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 -20Repository: 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.tsRepository: 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 -30Repository: 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.tsRepository: 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 -20Repository: 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.tsRepository: 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 tsRepository: 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 tsRepository: 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 -20Repository: 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 -80Repository: 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.tsRepository: 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.tsRepository: 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 -20Repository: 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.tsRepository: 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.tsRepository: 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 -10Repository: 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 -5Repository: 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.tsRepository: 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 -100Repository: 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.tsRepository: 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 tsRepository: 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 -20Repository: 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 -5Repository: 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 tsRepository: 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.tsRepository: 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 -20Repository: 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 -30Repository: 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.tsRepository: 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.tsRepository: 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.
| 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, | ||
| }); |
There was a problem hiding this comment.
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.
apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts
Show resolved
Hide resolved
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…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]>
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
|
/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) |
|
✅ 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... |
…39864) Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
|
|
||
| return API.default.success(makeOpenAPIResponse(getTypedRoutes(API.api.typedRoutes, { withUndocumented }))); | ||
| authRequired: false, | ||
| query: isOpenAPIJSONEndpoint, |
There was a problem hiding this comment.
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.'); |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
looks like we are returning 202 status code but we don't have such response schema
| }>({ | ||
| type: 'object', | ||
| properties: { | ||
| command: { type: 'string' }, |
There was a problem hiding this comment.
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' }, |
There was a problem hiding this comment.
same here with minLength: 1
There was a problem hiding this comment.
Also I think we should use ajvQuery rather than ajv
| query: isPushGetProps, | ||
| response: { | ||
| 200: pushGetResponseSchema, | ||
| 401: validateUnauthorizedErrorResponse, |
There was a problem hiding this comment.
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' }, |
There was a problem hiding this comment.
| statistics: { type: 'array' }, | |
| statistics: { type: 'array', items: { $ref: '#/components/schemas/IStats' } }, |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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] } }, |
There was a problem hiding this comment.
should we add missing: { type: 'array', items: { type: 'string' } } to properties? (as I see, missing is returned in line 1017) and additionalProperties: false
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
IMeApiUserfor user info and typed schemas for command endpoints, reducing ambiguity and improving maintainability. [1] [2] [3] [4]API Endpoint Refactoring
Replaced legacy
addRoutedefinitions with a new, more declarative.getand.postchaining 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
validateBadRequestErrorResponse,validateUnauthorizedErrorResponse, andvalidateForbiddenErrorResponsefor consistent error reporting. [1] [2] [3] [4]Minor Bug Fixes
subscription.lsis undefined.Minor Improvements
ApiClass.tsfor theforbiddenmethod, 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
New Features