Skip to content

feat(api): richer OpenAPI metadata for typed endpoints - #41638

Open
ggazzo wants to merge 16 commits into
developfrom
chore/api-openapi-metadata
Open

feat(api): richer OpenAPI metadata for typed endpoints#41638
ggazzo wants to merge 16 commits into
developfrom
chore/api-openapi-metadata

Conversation

@ggazzo

@ggazzo ggazzo commented Jul 30, 2026

Copy link
Copy Markdown
Member

Proposed changes (including videos or screenshots)

The document served at /api/docs/json was missing most of what makes an OpenAPI spec usable, and part of it was not even valid:

  • path parameters were emitted with Express syntax (/api/v1/banners/:id) and no parameters entries at all, so every /:id endpoint was unusable in Swagger UI and in generated clients;
  • query parameters were collapsed into a single opaque parameter named query holding the whole object schema, always marked as required;
  • responses[].description was hardcoded to '', and the field is required by the spec;
  • there was no way for an endpoint to declare a summary, a description, examples, or a deprecation notice;
  • unknown option keys (permissionsRequired, rateLimiterOptions, queryFields, typed) leaked into the operation object, and only when the route required auth;
  • schemas was duplicated at the root of the document, which is not an OpenAPI field.

The document is now OpenAPI 3.1

It declared 3.0.3 while carrying schemas written in JSON Schema 2020 - the dialect the endpoints validate against at runtime - so validators rejected 51 of them: union types, const, unevaluatedProperties, propertyNames. 3.1 is JSON Schema 2020, so declaring it makes the document honest and those errors disappear without touching a single schema. typia generates the component schemas for 3.1 as well.

Generating for 3.1 surfaced three places where its output no longer matched what AJV reads, all fixed where the schemas are generated:

  • tuples came out with prefixItems next to additionalItems, a keyword 2020 replaced with items. AJV aborts on the unknown keyword, which took the server down at boot;
  • nullable fields came out as oneOf: [{ type: 'null' }, { type: 'string' }]. The API validates with coerceTypes, which coerces the value for each branch until more than one matches, and then oneOf - exactly one - rejects a valid payload. Branches that only name a type collapse into a single type array;
  • discriminator.mapping, which AJV rejects outright: a validator that chokes on IMessage leaves every schema referencing it unresolvable, and one unsupported keyword became 38 errors in an external generator. What the mapping described is still in the const of each branch.

Single valued types also stopped being recognized by the heuristic that closes the plain file attachment branch, which had silently brought back an ambiguous oneOf; both spellings are recognized now.

Shared error payloads and explicit security

The four error payload schemas were inlined into every operation that declares them - 372 copies of the same schema, and of the same spec violation, since the details of a bad request allowed type: array with no items. A schema that carries an $id is now hoisted into components.schemas and referenced, so BadRequestError, UnauthorizedError, ForbiddenError and NotFoundError are described once.

Every operation also declares its security requirement: the auth headers when the route requires them, both the headers and nothing when it accepts anonymous access, and an empty list when it is public. Without it, a public endpoint is indistinguishable from one that forgot to declare anything, and validators flag all 19 of them.

Route options

Endpoints can now declare summary, description, operationId, deprecated, externalDocs, params, bodyContentType, responseDescriptions and examples. Everything else is derived from options the framework already needs:

Option already in use What the document gets
permissionsRequired x-permissions + a line in the description
license x-license + a line in the description
twoFactorRequired x-two-factor-required, the x-2fa-code/x-2fa-method header parameters, and a 403
deprecation deprecated: true + the target version and the alternatives
rateLimiterOptions the X-RateLimit-* response headers and a 429
authRequired security + a 401

Error responses implied by the route (400, 401, 403, 429, 500) are injected when the route does not declare them, and undocumented (legacy) routes get a generic 200 so their operation is at least valid.

Parameters

Path parameters are derived from the path pattern itself, so every {param} in the document has a matching parameter object; the optional params schema only adds descriptions, examples and types on top. Query schemas are exploded into one parameter per property with the real required flag, following allOf/anyOf/oneOf composition (allOf unions the requirements, anyOf/oneOf keep only the ones shared by every branch).

Self-documenting schemas

example is now registered as an AJV vocabulary, so a schema can carry its own description and example and have them flow straight into the document with no framework change. packages/rest-typings/src/v1/banners.ts shows the pattern.

Cleanup

Both copies of the conversion were replaced by a single builder in @rocket.chat/http-router. The copy living in APIClass wrote to a typedRoutes field that nothing ever read — the served document has always come from the router — so it and its legacy counterpart were removed. The three stale @openapi JSDoc blocks in banners.ts (dead since the switch to the runtime generator) were migrated into the route options and deleted.

Issue(s)

Steps to test or reproduce

  1. Start the server and open /api-docs; the banners endpoints now show a summary, a description, a typed id path parameter with an example, and a platform query field instead of a JSON blob.
  2. curl -s localhost:3000/api/docs/json | jq '.paths["/api/v1/banners/{id}"].get'
  3. curl -s 'localhost:3000/api/docs/json?withUndocumented=true' | jq -r '.paths | keys[]' | grep ':' returns nothing.
  4. Unit tests: yarn workspace @rocket.chat/http-router test
  5. API tests: apps/meteor/tests/end-to-end/api/openapi.ts asserts the invariants over every registered route — no Express syntax left, every path template has a parameter, every operation has at least one response and every response a description, unique operationIds, and undocumented routes stay hidden unless asked for.

Further comments

Measured on the document a running server generates, validated with redocly lint and with an AJV based validator: nullable 725 to 0, arrays without items 382 to 0, structural errors 51 to 0, unresolvable $ref 37 to 0, operations without security 19 to 0, success no longer at the root of the document. What is left is 58 operation-summary warnings, for endpoints nothing describes yet.

Bugs found while wiring this up:

  • operationId has to be generated by the document builder, not at registration time: routers register their operations before the parent router prefixes them, so generating it early produced getV1BannersId instead of getApiV1BannersId. It is now filled in by withOperationIds from the final path.
  • the implicit 403 was only injected for permissionsRequired in array form; the { POST: { operation, permissions } } shape was silently skipped.

Deliberately left out:

  • runtime validation of params — path values always arrive as strings and the endpoints already validate them, so the schema is documentation only (marked in the type);
  • mapping the legacy validateParams into query/body for documentation purposes: the router validates whatever it is given, so documenting those 274 legacy routes that way would enable a second round of validation on them;
  • committing an openapi.json artifact and adding spectral/oasdiff to CI. Worth doing next; the API test is the minimum gate in the meantime;
  • typing the items of the arrays whose schema had none: they carry items: {}, the empty schema, which is what the spec asks for and what validators accept, but documents nothing. Constraining them here would start rejecting real responses at runtime - details and the app logs really do hold anything the endpoint attached - so a meaningful shape has to be written per endpoint.

Review in cubic

Task: ARCH-2324

Summary by CodeRabbit

  • New Features

    • OpenAPI documentation now includes richer endpoint metadata, parameters, examples, response descriptions, authentication details, deprecation notices, and shared schemas.
    • API documentation is served using OpenAPI 3.1 through a streamlined JSON endpoint.
    • Banner endpoints now provide improved documentation and route-parameter validation.
  • Bug Fixes

    • Improved schema validation for arrays, nullable values, file attachments, error responses, and channel data.
  • Tests

    • Added comprehensive validation for documented routes, parameters, responses, security, and generated OpenAPI metadata.

@dionisio-bot

dionisio-bot Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

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

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

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot

changeset-bot Bot commented Jul 30, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f5a13bb

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

This PR includes changesets to release 3 packages
Name Type
@rocket.chat/rest-typings Patch
@rocket.chat/meteor Patch
@rocket.chat/core-typings Patch

Not sure what this means? Click here to learn what changesets are.

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

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This change adds typed OpenAPI 3.1 route documentation, converts AJV schemas, updates Meteor API integration, removes legacy typed-route metadata, and adds unit and end-to-end validation.

Changes

OpenAPI schema and router foundation

Layer / File(s) Summary
Schema compatibility and validation
packages/core-typings/src/Ajv.ts, packages/rest-typings/src/v1/*, apps/meteor/server/api/v1/*, apps/meteor/ee/server/apps/communication/endpoints/*
AJV schema generation converts JSON Schema 3.1 output. Endpoint schemas define explicit array items, examples, identifiers, and typed fallback properties.
Router OpenAPI operation generation
packages/http-router/src/openapi.ts, packages/http-router/src/Router.ts, packages/http-router/src/definition.ts, packages/http-router/src/index.ts, packages/http-router/src/*.spec.ts
The router exposes OpenAPI types and helpers. It normalizes paths, derives parameters, builds responses and metadata, hoists shared schemas, and assigns operation IDs.
Meteor API integration and validation
apps/meteor/server/api/ApiClass.ts, apps/meteor/server/api/default/openApi.ts, apps/meteor/server/api/definition.ts, apps/meteor/server/api/v1/banners.ts, apps/meteor/tests/end-to-end/api/openapi.ts, .changeset/*
Meteor removes legacy typed-route registration, uses route metadata for banners, serves an unwrapped OpenAPI 3.1 document, and validates the generated output.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested labels: type: feature

Suggested reviewers: sampaiodiego

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: enriching OpenAPI metadata for typed endpoints across the codebase, including path/query parameters, response descriptions, and endpoint documentation.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • ARCH-2324: Request failed with status code 401

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.

@ggazzo
ggazzo force-pushed the chore/api-openapi-metadata branch from 8fb5bc8 to 87107d3 Compare July 30, 2026 14:57
@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.25668% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.77%. Comparing base (cb7c5c2) to head (f5a13bb).
⚠️ Report is 11 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #41638      +/-   ##
===========================================
+ Coverage    68.75%   68.77%   +0.01%     
===========================================
  Files         4151     4156       +5     
  Lines       159513   159825     +312     
  Branches     27997    28070      +73     
===========================================
+ Hits        109681   109927     +246     
- Misses       44657    44722      +65     
- Partials      5175     5176       +1     
Flag Coverage Δ
e2e 58.84% <ø> (-0.03%) ⬇️
e2e-api 45.73% <91.66%> (-0.25%) ⬇️
unit 70.76% <96.57%> (+0.05%) ⬆️

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.

The generated OpenAPI document was missing most of what makes a spec usable:
path parameters were emitted with Express syntax and no parameter objects,
query parameters were collapsed into a single opaque `query` object, response
descriptions were hardcoded as empty strings, and there was no way for an
endpoint to declare a summary, a description, examples or a deprecation notice.

Route options now accept `summary`, `description`, `operationId`, `deprecated`,
`externalDocs`, `params`, `bodyContentType`, `responseDescriptions` and
`examples`. Everything else is derived from options the framework already has:
permissions, license modules and two-factor requirements become `x-*`
extensions plus a note in the description, `deprecation` sets `deprecated`,
rate limiting documents its response headers and `429`, and the error responses
implied by the route (400, 401, 403, 429, 500) are injected when not declared.

Path parameters are now derived from the path pattern itself, so every `{param}`
in the document has a matching parameter object, and query schemas are exploded
into one parameter per property, honoring `allOf`/`anyOf`/`oneOf` composition.

Both copies of the OpenAPI conversion were replaced by a single builder in
`@rocket.chat/http-router`. The copy living in `APIClass` wrote to a
`typedRoutes` field that nothing ever read - the served document has always
come from the router - so it was removed along with its legacy counterpart.

The `example` annotation is now registered as an AJV vocabulary, so schemas can
carry their own `description` and `example` and have them flow straight into the
document. The banners endpoints show the pattern and drop the stale `@openapi`
JSDoc blocks that nothing had been reading.
@ggazzo
ggazzo force-pushed the chore/api-openapi-metadata branch from 87107d3 to d991e7a Compare July 30, 2026 15:17
ggazzo added 2 commits July 30, 2026 15:23
`swaggerUi.setup` runs at import time, before settings are loaded, so
`settings.get('Site_Url')` was interpolated as `undefined` and the UI ended up
fetching `/api-docs/undefined/api/docs/json`. The served HTML came back instead
of the spec, and Swagger UI reported a missing `openapi` version field.

The document is always served from the same origin as the UI, so a relative url
needs no setting at all.
Auditing the hand-written definitions in RocketChat/Rocket.Chat-Open-API showed
which features the published documentation relies on and this framework could
not express:

- named example scenarios, by far the most used feature there (1010 example
  objects, 156 payloads documenting two to six alternatives). `examples.body`
  and `examples.response[code]` now accept either a single value or a map of
  named Example Objects with their own summary and description;
- a response content type per status code, for the endpoints answering images,
  plain text or files instead of JSON;
- response headers per status code, merged with the rate limit ones the router
  already documents.

`operationId` now follows the convention of the ids published at
developer.rocket.chat (`get-api-v1-banners-id`) instead of a camel case variant,
so deep links and generated clients survive the change of source.

Documented paths also collapse duplicate slashes, which were leaking into three
path keys (`/api//info`, `/api//docs/json`, `/api/apps//{id}/export-logs`) when a
router prefixed a subpath that already started with one.
ggazzo added 11 commits July 31, 2026 11:07
The four error payload schemas were inlined into every operation that declares
them, so the document repeated them 372 times - and repeated the same spec
violation with them: the `details` field of a bad request allowed `type: array`
with no `items`, which no OpenAPI tool accepts.

A schema that carries an `$id` is now hoisted into `components.schemas` and
referenced, so `BadRequestError`, `UnauthorizedError`, `ForbiddenError` and
`NotFoundError` are described once. The mechanism is generic: any shared schema
that names itself is deduplicated the same way.

Also adds the missing `items` to the two arrays that lacked it - the `details` of
a bad request and the `logs` of the app log endpoints. Both are left as an empty
schema on purpose: the keyword is required on arrays, but the payloads really do
hold anything the endpoint attached, and constraining them here would start
rejecting responses at runtime.
`/api/docs/json` answered `API.default.success(document)`, which adds a `success`
key to the root of the document. It is not an OpenAPI field, and validators
reject it (`Property 'success' is not expected here` at `#/`).

Also adds `items` to the eight remaining arrays whose schema lacked it - the spec
requires the keyword on every array, and validators refuse the schema without it.
The document declared 3.0.3 while carrying schemas written in JSON Schema 2020,
the dialect the endpoints validate against at runtime. Validators rejected 51 of
them: union types (`type: ["number", "null"]`, 39 of them), `const` (9),
`unevaluatedProperties` and `propertyNames`.

OpenAPI 3.1 *is* JSON Schema 2020, so declaring it makes the document honest and
all 51 errors disappear without touching a single schema. `typia` now generates
its component schemas for 3.1 as well, which drops `nullable` in favour of the
union types 3.1 accepts.

The UI we serve (swagger-ui 5) renders 3.1 documents.
Generating the component schemas for OpenAPI 3.1 exposed two places where typia's
output no longer matched what the runtime expects:

- tuples come out with `prefixItems` (JSON Schema 2020) next to `additionalItems`,
  a keyword 2020 replaced with `items`. AJV runs in 2020 and aborts on the unknown
  keyword - `Error: strict mode: unknown keyword: "additionalItems"` - taking the
  server down at boot. The rename happens once, on the generated output, together
  with the `minItems` a closed tuple implies and AJV asks for;
- single valued types come out as `const` instead of `enum`, which silently broke
  the heuristic that locks down the plain file attachment branch, bringing back the
  ambiguous `oneOf` that fails response validation for messages carrying files.
  Both spellings are now recognized.

AJV also implements `discriminator` but rejects its `mapping`, which 3.1 output
includes. It is dropped from the copy AJV compiles, and kept in the one the
document serializes, where it is what tools actually use.
Declaring the document as 3.1 left 725 structural errors behind: `nullable`, the
way 3.0 marked a field as accepting null, is not a JSON Schema keyword, so 3.1
rejects it. The 895 schemas that use it keep it - AJV understands it - and the
document now carries the 3.1 equivalent instead, a `null` member of `type`,
converted on a copy while each operation is built.

Also drops the trailing slash from the server url, which `Site_Url` often carries
and which would make every path in the document resolve with a double one.
The document declares security schemes, so an operation with no `security` field
is indistinguishable from one that forgot to declare it, and validators flag all
19 public endpoints (`shield.svg`, `pw.getPolicy`, `method.callAnon` and friends).

Every operation now spells its requirement out: the auth headers when the route
requires them, both the headers and nothing when it accepts anonymous access, and
an empty list when it is public.
A validator that compiles the component schemas with AJV cannot register
`IMessage`, `IRoom`, `IIntegrationHistory`, `PartialIMessage` or `IUploadWithUser`,
because AJV implements `discriminator` but rejects its `mapping`. Everything that
references those schemas then reports `can't resolve reference`, which is how one
unsupported keyword turns into 38 errors and stops a generator that refuses to run
on an invalid document.

The mapping is now dropped where the schemas are generated, so the document and
the runtime share it, and the strip the API bootstrap did for AJV alone is gone.
What the mapping described is still there: each branch carries the `const` of its
discriminating property.

Also defines the `_id` and `t` that the loose `channels.info` branch requires, so
the schema stops requiring properties it never declares.
Every 2xx body is typed as `{ success: true } & T`, so returning the OpenAPI document without the envelope did not compile - and the lint task, which runs the same typecheck, failed with it.
…ypes

Every route exports its options to its callers through `Endpoints`, minus the
response validators. With documentation in those options - summary, description,
examples, tags - the augmentation grew a type graph large enough to collapse:
`Type 'Endpoints' recursively references itself as a base type`, fifty times, and
two thousand errors cascading through the client that consumes those types.

Documentation describes an endpoint for readers and has no place in the type its
callers see, so it is omitted alongside the response validators.

Also destructures in the test what the lint rule asks to destructure.
Omitting summary, description, examples and tags from what `Endpoints` exposes did
not stop the augmentation from collapsing: the trigger is the tags being declared
in the route options at all, not what the type exposes afterwards. The fix belongs
where the tags are written, so this goes back to what it was.
Generating for 3.1 turned every nullable field into `oneOf: [{ type: 'null' },
{ type: 'string' }]`, where 3.0 wrote `nullable`. The API validates responses with
`coerceTypes`, which coerces the value for each branch in turn until more than one
matches - and then `oneOf`, meaning exactly one, rejects a perfectly valid payload:

    at path '/data/9/users/0/avatarETag': must match exactly one schema in oneOf
    (passingSchemas: 0,1)

That is what took `video-conference.list` down in the apps test suite. Branches that
only name a type now collapse into a single `type` array, which says the same thing
and leaves nothing to disambiguate. Verified against the payload from the failing
run: it validates with the collapse and reproduces the failure without it.

The discriminator strip is also scoped to the discriminator now, instead of dropping
any property named `mapping` wherever it appeared.
@ggazzo ggazzo added this to the 8.8.0 milestone Aug 3, 2026
@ggazzo

ggazzo commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

/jira ARCH-1464

@ggazzo
ggazzo marked this pull request as ready for review August 3, 2026 14:53
@ggazzo
ggazzo requested review from a team as code owners August 3, 2026 14:53
@coderabbitai coderabbitai Bot added the type: feature Pull requests that introduces new feature label Aug 3, 2026

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 5

🧹 Nitpick comments (5)
packages/core-typings/src/Ajv.ts (1)

75-92: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove implementation comments from these TypeScript files.

These new comments violate the repository TypeScript guideline.

  • packages/core-typings/src/Ajv.ts#L75-L92: remove the normalization rationale comment.
  • packages/rest-typings/src/v1/Ajv.ts#L23-L24: remove the AJV vocabulary comment.
  • packages/rest-typings/src/v1/Ajv.ts#L66-L67: remove the unrestricted-array comment.
  • apps/meteor/server/api/validation/ajv.ts#L27-L28: remove the Typia version-format comment.

As per coding guidelines, “Avoid code comments in the implementation.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core-typings/src/Ajv.ts` around lines 75 - 92, Remove the
implementation rationale comments at packages/core-typings/src/Ajv.ts lines
75-92, packages/rest-typings/src/v1/Ajv.ts lines 23-24 and 66-67, and
apps/meteor/server/api/validation/ajv.ts lines 27-28, while leaving the
surrounding AJV normalization and validation logic unchanged.

Source: Coding guidelines

packages/http-router/src/openapi.spec.ts (1)

27-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add an assertion for the optional path segment parameter.

The suite converts /api/v1/settings/:_id? to a templated path, but it never asserts the resulting parameter object. Add a case that checks the required flag of the derived parameter for an optional segment. This locks the behavior discussed on packages/http-router/src/openapi.ts Lines 284-304.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/http-router/src/openapi.spec.ts` around lines 27 - 36, The
toOpenAPIPath tests only verify the converted path string, not the optional
parameter metadata. Extend the relevant test coverage around toOpenAPIPath to
inspect the derived OpenAPI parameter for the optional _id segment and assert
that its required flag is false.
apps/meteor/tests/end-to-end/api/openapi.ts (1)

84-93: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a test that every $ref resolves inside components.schemas.

The router hoists any schema carrying an $id into components.schemas and replaces it with a $ref. No test verifies that each emitted $ref target exists. A dangling reference breaks Swagger UI and code generators while every current assertion still passes. Walk the document, collect each $ref value, and assert the referenced key exists.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/meteor/tests/end-to-end/api/openapi.ts` around lines 84 - 93, Extend the
OpenAPI validation tests near “should name and schema every parameter” to
recursively walk the generated document, collect every $ref value, and verify
each target key exists in components.schemas. Preserve the existing parameter
assertions and ensure references emitted by the router’s $id hoisting are
checked for dangling targets.
packages/http-router/src/openapi.ts (1)

229-248: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Detect conflicting $id registrations in sharedSchemas.

referenceSchema writes into the module-level sharedSchemas map keyed only by $id. The repository compiles schemas with several AJV instances (for example ajv and ajvQuery in packages/rest-typings), so AJV cannot detect a duplicate $id across instances. If two different schemas share an $id, the last registration wins and every operation that referenced the first one points at the wrong schema. Consider comparing an incoming definition with an existing entry and failing fast on a mismatch.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/http-router/src/openapi.ts` around lines 229 - 248, Update
referenceSchema to detect conflicting definitions before overwriting an existing
sharedSchemas entry: when the same $id is already registered, compare the
incoming definition with the stored one and fail fast if they differ; retain the
existing entry and reference behavior when they match, while preserving
registration for new IDs.
packages/rest-typings/src/default/index.ts (1)

53-83: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Declare the new root fields in the /docs/json response type.

makeOpenAPIResponse in apps/meteor/server/api/default/openApi.ts now emits externalDocs and tags at the document root. This type does not declare them, so typed clients cannot read those fields. Add them to keep the endpoint type aligned with the served document.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/rest-typings/src/default/index.ts` around lines 53 - 83, Update the
/docs/json GET response type in the endpoint definitions to declare the
root-level externalDocs and tags fields emitted by makeOpenAPIResponse,
preserving their OpenAPI document shapes so typed clients can access them.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/meteor/server/api/default/openApi.ts`:
- Around line 75-80: Update the OpenAPI document construction around the servers
configuration to omit the entire servers entry when Site_Url is unset, rather
than creating a Server Object with an undefined url. Preserve the existing
trailing-slash removal when Site_Url is present and ensure the resulting
document contains no servers array in the unset case.

In `@packages/http-router/src/openapi.ts`:
- Around line 284-304: The OpenAPI path parameter builder must mark every
templated path parameter as required, including Express optional segments. In
packages/http-router/src/openapi.ts lines 284-304, update buildPathParameters or
extractPathParameterNames so derived parameters use required: true. In
packages/http-router/src/openapi.spec.ts lines 27-36, add coverage for
/api/v1/settings/:_id? and assert the derived parameter includes required: true.
- Around line 465-472: Update the response-status check guarding the injected
response in the OpenAPI generation flow so any declared status below 400 counts
as a documented outcome, including redirects such as 302 and 307. Preserve the
existing fallback 200 response for routes with no declared status below 400.
- Around line 214-219: Update the nullable handling in toOpenAPI31 so primitive
string types retain the existing type-plus-null behavior, arrays return
rest.type after ensuring null is included, and missing or non-array type schemas
are not spread as string arrays. Specifically guard the final branch against
absent or object-valued rest.type and return the schema safely for type: {
nullable: true }.

In `@packages/http-router/src/Router.ts`:
- Around line 339-344: Update the typedRoutes merge in the Router method
handling innerRouter. When multiple entries normalize to the same OpenAPI path,
preserve the existing method map from this.typedRoutes and merge the nested
routes into it rather than replacing the entire map; ensure nested methods
override only matching methods while parent-only operations remain.

---

Nitpick comments:
In `@apps/meteor/tests/end-to-end/api/openapi.ts`:
- Around line 84-93: Extend the OpenAPI validation tests near “should name and
schema every parameter” to recursively walk the generated document, collect
every $ref value, and verify each target key exists in components.schemas.
Preserve the existing parameter assertions and ensure references emitted by the
router’s $id hoisting are checked for dangling targets.

In `@packages/core-typings/src/Ajv.ts`:
- Around line 75-92: Remove the implementation rationale comments at
packages/core-typings/src/Ajv.ts lines 75-92,
packages/rest-typings/src/v1/Ajv.ts lines 23-24 and 66-67, and
apps/meteor/server/api/validation/ajv.ts lines 27-28, while leaving the
surrounding AJV normalization and validation logic unchanged.

In `@packages/http-router/src/openapi.spec.ts`:
- Around line 27-36: The toOpenAPIPath tests only verify the converted path
string, not the optional parameter metadata. Extend the relevant test coverage
around toOpenAPIPath to inspect the derived OpenAPI parameter for the optional
_id segment and assert that its required flag is false.

In `@packages/http-router/src/openapi.ts`:
- Around line 229-248: Update referenceSchema to detect conflicting definitions
before overwriting an existing sharedSchemas entry: when the same $id is already
registered, compare the incoming definition with the stored one and fail fast if
they differ; retain the existing entry and reference behavior when they match,
while preserving registration for new IDs.

In `@packages/rest-typings/src/default/index.ts`:
- Around line 53-83: Update the /docs/json GET response type in the endpoint
definitions to declare the root-level externalDocs and tags fields emitted by
makeOpenAPIResponse, preserving their OpenAPI document shapes so typed clients
can access them.
🪄 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 Plus

Run ID: 0076f859-3787-4a1a-9bcb-f79a5c857d20

📥 Commits

Reviewing files that changed from the base of the PR and between cb7c5c2 and ae7766b.

📒 Files selected for processing (24)
  • .changeset/loud-otters-document.md
  • .changeset/plain-lions-agree.md
  • apps/meteor/ee/server/apps/communication/endpoints/appGeneralLogsHandler.ts
  • apps/meteor/ee/server/apps/communication/endpoints/appLogsHandler.ts
  • apps/meteor/server/api/ApiClass.ts
  • apps/meteor/server/api/default/openApi.ts
  • apps/meteor/server/api/definition.ts
  • apps/meteor/server/api/v1/banners.ts
  • apps/meteor/server/api/v1/channels.ts
  • apps/meteor/server/api/v1/misc.ts
  • apps/meteor/server/api/v1/stats.ts
  • apps/meteor/server/api/v1/users.ts
  • apps/meteor/server/api/validation/ajv.ts
  • apps/meteor/tests/end-to-end/api/openapi.ts
  • packages/core-typings/src/Ajv.ts
  • packages/http-router/src/Router.spec.ts
  • packages/http-router/src/Router.ts
  • packages/http-router/src/definition.ts
  • packages/http-router/src/index.ts
  • packages/http-router/src/openapi.spec.ts
  • packages/http-router/src/openapi.ts
  • packages/rest-typings/src/default/index.ts
  • packages/rest-typings/src/v1/Ajv.ts
  • packages/rest-typings/src/v1/banners.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (11)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Hacktron Security Check
  • GitHub Check: 🔨 Test UI (EE) / MongoDB 8.0 coverage (5/5)
  • GitHub Check: 🔨 Test UI (EE) / MongoDB 8.0 coverage (1/5)
  • GitHub Check: 🔨 Test UI (EE) / MongoDB 8.0 coverage (3/5)
  • GitHub Check: 🔨 Test UI (EE) / MongoDB 8.0 coverage (2/5)
  • GitHub Check: 🔨 Test UI (EE) / MongoDB 8.0 coverage (4/5)
  • GitHub Check: 🔨 Test UI (CE) / MongoDB 8.0 (3/4)
  • GitHub Check: 🔨 Test UI (CE) / MongoDB 8.0 (1/4)
  • GitHub Check: 🔨 Test UI (CE) / MongoDB 8.0 (2/4)
  • GitHub Check: 🔨 Test UI (CE) / MongoDB 8.0 (4/4)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • packages/http-router/src/index.ts
  • apps/meteor/ee/server/apps/communication/endpoints/appGeneralLogsHandler.ts
  • apps/meteor/server/api/v1/misc.ts
  • apps/meteor/server/api/v1/channels.ts
  • packages/http-router/src/Router.spec.ts
  • apps/meteor/server/api/definition.ts
  • packages/http-router/src/definition.ts
  • packages/rest-typings/src/default/index.ts
  • apps/meteor/server/api/validation/ajv.ts
  • packages/http-router/src/openapi.spec.ts
  • apps/meteor/ee/server/apps/communication/endpoints/appLogsHandler.ts
  • packages/rest-typings/src/v1/Ajv.ts
  • apps/meteor/server/api/v1/stats.ts
  • apps/meteor/tests/end-to-end/api/openapi.ts
  • packages/rest-typings/src/v1/banners.ts
  • apps/meteor/server/api/v1/banners.ts
  • apps/meteor/server/api/v1/users.ts
  • packages/core-typings/src/Ajv.ts
  • apps/meteor/server/api/default/openApi.ts
  • apps/meteor/server/api/ApiClass.ts
  • packages/http-router/src/Router.ts
  • packages/http-router/src/openapi.ts
**/*.spec.ts

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.spec.ts: Use descriptive test names that clearly communicate expected behavior in Playwright tests
Use .spec.ts extension for test files (e.g., login.spec.ts)

Files:

  • packages/http-router/src/Router.spec.ts
  • packages/http-router/src/openapi.spec.ts
🧠 Learnings (10)
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • packages/http-router/src/index.ts
  • apps/meteor/ee/server/apps/communication/endpoints/appGeneralLogsHandler.ts
  • apps/meteor/server/api/v1/misc.ts
  • apps/meteor/server/api/v1/channels.ts
  • packages/http-router/src/Router.spec.ts
  • apps/meteor/server/api/definition.ts
  • packages/http-router/src/definition.ts
  • packages/rest-typings/src/default/index.ts
  • apps/meteor/server/api/validation/ajv.ts
  • packages/http-router/src/openapi.spec.ts
  • apps/meteor/ee/server/apps/communication/endpoints/appLogsHandler.ts
  • packages/rest-typings/src/v1/Ajv.ts
  • apps/meteor/server/api/v1/stats.ts
  • apps/meteor/tests/end-to-end/api/openapi.ts
  • packages/rest-typings/src/v1/banners.ts
  • apps/meteor/server/api/v1/banners.ts
  • apps/meteor/server/api/v1/users.ts
  • packages/core-typings/src/Ajv.ts
  • apps/meteor/server/api/default/openApi.ts
  • apps/meteor/server/api/ApiClass.ts
  • packages/http-router/src/Router.ts
  • packages/http-router/src/openapi.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • packages/http-router/src/index.ts
  • apps/meteor/ee/server/apps/communication/endpoints/appGeneralLogsHandler.ts
  • apps/meteor/server/api/v1/misc.ts
  • apps/meteor/server/api/v1/channels.ts
  • packages/http-router/src/Router.spec.ts
  • apps/meteor/server/api/definition.ts
  • packages/http-router/src/definition.ts
  • packages/rest-typings/src/default/index.ts
  • apps/meteor/server/api/validation/ajv.ts
  • packages/http-router/src/openapi.spec.ts
  • apps/meteor/ee/server/apps/communication/endpoints/appLogsHandler.ts
  • packages/rest-typings/src/v1/Ajv.ts
  • apps/meteor/server/api/v1/stats.ts
  • apps/meteor/tests/end-to-end/api/openapi.ts
  • packages/rest-typings/src/v1/banners.ts
  • apps/meteor/server/api/v1/banners.ts
  • apps/meteor/server/api/v1/users.ts
  • packages/core-typings/src/Ajv.ts
  • apps/meteor/server/api/default/openApi.ts
  • apps/meteor/server/api/ApiClass.ts
  • packages/http-router/src/Router.ts
  • packages/http-router/src/openapi.ts
📚 Learning: 2026-05-06T12:21:44.083Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 40256
File: apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx:121-149
Timestamp: 2026-05-06T12:21:44.083Z
Learning: Field wrappers in rocket.chat/fuselage-forms (Field, FieldLabel, FieldRow, FieldError, FieldHint) auto-create htmlFor/id associations, aria-describedby, and role="alert" for errors. Do not manually set htmlFor, id, aria-describedby, or role attributes when using these wrappers. This automatic wiring does not apply to plain rocket.chat/fuselage components, which require explicit ID wiring per the accessibility docs. In code reviews, prefer using fuselage-forms wrappers for form fields and verify there is no unnecessary manual ID/aria wiring in files that use these wrappers. If a component uses plain fuselage components, ensure proper id wiring as per docs.

Applied to files:

  • packages/http-router/src/index.ts
  • apps/meteor/ee/server/apps/communication/endpoints/appGeneralLogsHandler.ts
  • apps/meteor/server/api/v1/misc.ts
  • apps/meteor/server/api/v1/channels.ts
  • packages/http-router/src/Router.spec.ts
  • apps/meteor/server/api/definition.ts
  • packages/http-router/src/definition.ts
  • packages/rest-typings/src/default/index.ts
  • apps/meteor/server/api/validation/ajv.ts
  • packages/http-router/src/openapi.spec.ts
  • apps/meteor/ee/server/apps/communication/endpoints/appLogsHandler.ts
  • packages/rest-typings/src/v1/Ajv.ts
  • apps/meteor/server/api/v1/stats.ts
  • apps/meteor/tests/end-to-end/api/openapi.ts
  • packages/rest-typings/src/v1/banners.ts
  • apps/meteor/server/api/v1/banners.ts
  • apps/meteor/server/api/v1/users.ts
  • packages/core-typings/src/Ajv.ts
  • apps/meteor/server/api/default/openApi.ts
  • apps/meteor/server/api/ApiClass.ts
  • packages/http-router/src/Router.ts
  • packages/http-router/src/openapi.ts
📚 Learning: 2026-03-16T21:50:37.589Z
Learnt from: amitb0ra
Repo: RocketChat/Rocket.Chat PR: 39676
File: .changeset/migrate-users-register-openapi.md:3-3
Timestamp: 2026-03-16T21:50:37.589Z
Learning: For changes related to OpenAPI migrations in Rocket.Chat/OpenAPI, when removing endpoint types and validators from rocket.chat/rest-typings (e.g., UserRegisterParamsPOST, /v1/users.register) document this as a minor changeset (not breaking) per RocketChat/Rocket.Chat-Open-API#150 Rule 7. Note that the endpoint type is re-exposed via a module augmentation .d.ts in the consuming package (e.g., packages/web-ui-registration/src/users-register.d.ts). In reviews, ensure the changeset clearly states: this is a non-breaking change, the major version should not be bumped, and the changeset reflects a minor version bump. Do not treat this as a breaking change during OpenAPI migrations.

Applied to files:

  • .changeset/plain-lions-agree.md
  • .changeset/loud-otters-document.md
📚 Learning: 2026-07-29T23:45:21.859Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 41632
File: apps/meteor/server/api/v1/groups.ts:948-959
Timestamp: 2026-07-29T23:45:21.859Z
Learning: For API v1 routes under apps/meteor/server/api/v1, keep item-level response schemas strict by using `$ref`-based schemas for list and messages (and ensure they intentionally mirror the corresponding route contracts, as done in channels.ts). Only use “loose”/non-`$ref` item schemas when the underlying data source is inherently partial (e.g., uploads where `content` can be `null`, or queries like `findUsersOfRoom` with a fixed projection). Do not relax item schemas merely because the route supports an optional client `fields` projection—optional field selection alone is not a reason to change schema strictness.

Applied to files:

  • apps/meteor/server/api/v1/misc.ts
  • apps/meteor/server/api/v1/channels.ts
  • apps/meteor/server/api/v1/stats.ts
  • apps/meteor/server/api/v1/banners.ts
  • apps/meteor/server/api/v1/users.ts
📚 Learning: 2026-07-31T02:44:35.111Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 41635
File: apps/meteor/ee/server/api/sessions.ts:114-138
Timestamp: 2026-07-31T02:44:35.111Z
Learning: In Rocket.Chat typed REST response schemas, accept the composition of a Typia-generated entity schema with an `allOf` branch requiring `success: true`: `allOf: [{ $ref: <entity schema> }, { properties: { success: { type: 'boolean', enum: [true] } }, required: ['success'] }]`. Do not flag this pattern when used for REST endpoints, provided TEST_MODE response validation passes, as demonstrated by the `IOAuthApps` and `IEmailInbox` endpoints.

Applied to files:

  • apps/meteor/server/api/v1/misc.ts
  • apps/meteor/server/api/v1/channels.ts
  • apps/meteor/server/api/definition.ts
  • apps/meteor/server/api/validation/ajv.ts
  • apps/meteor/server/api/v1/stats.ts
  • apps/meteor/server/api/v1/banners.ts
  • apps/meteor/server/api/v1/users.ts
  • apps/meteor/server/api/default/openApi.ts
  • apps/meteor/server/api/ApiClass.ts
📚 Learning: 2025-12-10T21:00:43.645Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37091
File: ee/packages/abac/jest.config.ts:4-7
Timestamp: 2025-12-10T21:00:43.645Z
Learning: Adopt the monorepo-wide Jest testMatch pattern: <rootDir>/src/**/*.spec.{ts,js,mjs} (represented here as '**/src/**/*.spec.{ts,js,mjs}') to ensure spec files under any package's src directory are picked up consistently across all packages in the Rocket.Chat monorepo. Apply this pattern in jest.config.ts for all relevant packages to maintain uniform test discovery.

Applied to files:

  • packages/http-router/src/Router.spec.ts
  • packages/http-router/src/openapi.spec.ts
📚 Learning: 2026-02-24T19:22:48.358Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 38493
File: apps/meteor/tests/e2e/omnichannel/omnichannel-send-pdf-transcript.spec.ts:66-67
Timestamp: 2026-02-24T19:22:48.358Z
Learning: In Playwright end-to-end tests (e.g., under apps/meteor/tests/e2e/...), prefer locating elements by translated text (getByText) and ARIA roles (getByRole) over data-qa attributes. If translation values change, update the corresponding test locators accordingly. Never use data-qa locators. This guideline applies to all Playwright e2e test specs in the repository and helps keep tests robust to UI text changes and accessible semantics.

Applied to files:

  • packages/http-router/src/Router.spec.ts
  • packages/http-router/src/openapi.spec.ts
📚 Learning: 2026-03-06T18:10:15.268Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39397
File: packages/gazzodown/src/code/CodeBlock.spec.tsx:47-68
Timestamp: 2026-03-06T18:10:15.268Z
Learning: In tests (especially those using testing-library/dom/jsdom) for Rocket.Chat components, the HTML <code> element has an implicit ARIA role of 'code'. Therefore, screen.getByRole('code') or screen.findByRole('code') will locate <code> elements even without a role attribute. Do not flag findByRole('code') as invalid in reviews; prefer using the implicit role instead of adding role="code" unless necessary for accessibility.

Applied to files:

  • packages/http-router/src/Router.spec.ts
  • packages/http-router/src/openapi.spec.ts
📚 Learning: 2026-05-11T23:14:59.316Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 40469
File: packages/rest-typings/src/v1/users.ts:337-337
Timestamp: 2026-05-11T23:14:59.316Z
Learning: In Rocket.Chat REST endpoint typings (e.g., packages/rest-typings/src/v1/users.ts and other rest-typings files), keep the established convention of deriving field types from the domain model (e.g., use IUser indexed access like IUser['statusExpiresAt']) rather than swapping individual fields to serialized primitives (like string) in an ad-hoc way. If a truly different “serialized” representation is needed, perform the refactor consistently across the codebase (not just a single endpoint/field) and ensure all related REST typings stay aligned with the shared serialization types.

Applied to files:

  • packages/rest-typings/src/default/index.ts
  • packages/rest-typings/src/v1/Ajv.ts
  • packages/rest-typings/src/v1/banners.ts
🔇 Additional comments (33)
packages/core-typings/src/Ajv.ts (1)

32-73: LGTM!

Also applies to: 93-129

packages/rest-typings/src/v1/Ajv.ts (1)

25-26: LGTM!

Also applies to: 59-65, 68-68, 85-85, 109-109, 130-130

packages/rest-typings/src/v1/banners.ts (2)

19-20: LGTM!

Also applies to: 29-40, 54-55


42-42: 🎯 Functional Correctness

No duplicate declaration issue remains.

The referenced declarations each occur only once in their respective blocks.

			> Likely an incorrect or invalid review comment.
apps/meteor/ee/server/apps/communication/endpoints/appGeneralLogsHandler.ts (1)

36-36: LGTM!

apps/meteor/ee/server/apps/communication/endpoints/appLogsHandler.ts (1)

34-34: LGTM!

apps/meteor/server/api/v1/channels.ts (1)

136-144: LGTM!

apps/meteor/server/api/v1/misc.ts (1)

498-498: LGTM!

apps/meteor/server/api/v1/stats.ts (1)

27-27: LGTM!

apps/meteor/server/api/v1/users.ts (1)

787-787: LGTM!

Also applies to: 1522-1522, 1683-1683, 1832-1832

apps/meteor/server/api/validation/ajv.ts (1)

30-31: LGTM!

packages/http-router/src/Router.spec.ts (1)

755-784: LGTM!

.changeset/plain-lions-agree.md (1)

1-6: LGTM!

packages/http-router/src/openapi.ts (6)

3-110: LGTM!


306-332: LGTM!


334-412: LGTM!


414-439: LGTM!


483-520: LGTM!


522-531: LGTM!

packages/http-router/src/Router.ts (1)

10-11: LGTM!

Also applies to: 79-82

packages/http-router/src/definition.ts (1)

5-6: LGTM!

Also applies to: 49-59

packages/http-router/src/index.ts (1)

2-2: LGTM!

packages/http-router/src/openapi.spec.ts (2)

1-25: LGTM!


274-325: LGTM!

apps/meteor/server/api/v1/banners.ts (1)

5-5: LGTM!

Also applies to: 35-46, 67-76, 96-105

apps/meteor/server/api/default/openApi.ts (4)

3-11: LGTM!

Also applies to: 46-61


104-117: LGTM!


131-137: LGTM!


146-148: No change needed. docs/json sets authRequired: false, so Swagger UI can fetch the relative URL without authentication headers.

apps/meteor/tests/end-to-end/api/openapi.ts (1)

1-45: LGTM!

apps/meteor/server/api/ApiClass.ts (1)

2-2: No change needed for typedRoutes usage.

API.api is a RocketChatAPIRouter, and Router exposes typedRoutes; no remaining APIClass.typedRoutes consumers exist.

.changeset/loud-otters-document.md (1)

1-6: No action required.

@rocket.chat/http-router is private, so separate .changeset entries should not include it, even though the package gained OpenAPI-related exports/type changes.

			> Likely an incorrect or invalid review comment.
apps/meteor/server/api/definition.ts (1)

289-299: No change needed. SharedOptions and OpenAPIDocumentation do not redeclare the OpenAPI documentation properties with conflicting types.

Comment thread apps/meteor/server/api/default/openApi.ts Outdated
Comment thread packages/http-router/src/openapi.ts Outdated
Comment thread packages/http-router/src/openapi.ts Outdated
Comment thread packages/http-router/src/openapi.ts Outdated
Comment thread packages/http-router/src/Router.ts Outdated

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

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.

1 issue found across 24 files

Prompt for AI agents (unresolved issues)

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


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

<violation number="1" location="apps/meteor/server/api/v1/stats.ts:27">
P3: `items: {}` is an empty JSON Schema, so in the generated OpenAPI document the statistics.paginated list endpoint's array items render as an untyped placeholder rather than the actual element shape. Since the goal of this PR is richer OpenAPI metadata, this doesn't add useful item documentation and is effectively a no-op (any value passes it). Consider typing the items (e.g. `items: { type: 'object' }`), or better, referencing the `IStats` schema, so consumers of `/api/docs/json` get a meaningful item type.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread apps/meteor/server/api/default/openApi.ts Outdated
Comment thread packages/core-typings/src/Ajv.ts
Comment thread packages/http-router/src/Router.ts
Comment thread packages/http-router/src/openapi.ts Outdated
Comment thread .changeset/plain-lions-agree.md
Comment thread packages/core-typings/src/Ajv.ts Outdated
type: 'object',
properties: {
statistics: { type: 'array' },
statistics: { type: 'array', items: {} },

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.

P3: items: {} is an empty JSON Schema, so in the generated OpenAPI document the statistics.paginated list endpoint's array items render as an untyped placeholder rather than the actual element shape. Since the goal of this PR is richer OpenAPI metadata, this doesn't add useful item documentation and is effectively a no-op (any value passes it). Consider typing the items (e.g. items: { type: 'object' }), or better, referencing the IStats schema, so consumers of /api/docs/json get a meaningful item type.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/meteor/server/api/v1/stats.ts, line 27:

<comment>`items: {}` is an empty JSON Schema, so in the generated OpenAPI document the statistics.paginated list endpoint's array items render as an untyped placeholder rather than the actual element shape. Since the goal of this PR is richer OpenAPI metadata, this doesn't add useful item documentation and is effectively a no-op (any value passes it). Consider typing the items (e.g. `items: { type: 'object' }`), or better, referencing the `IStats` schema, so consumers of `/api/docs/json` get a meaningful item type.</comment>

<file context>
@@ -24,7 +24,7 @@ const statisticsResponseSchema = ajv.compile<IStats>({
 	type: 'object',
 	properties: {
-		statistics: { type: 'array' },
+		statistics: { type: 'array', items: {} },
 		count: { type: 'number' },
 		offset: { type: 'number' },
</file context>

Comment thread apps/meteor/tests/end-to-end/api/openapi.ts Outdated
ggazzo added 2 commits August 3, 2026 15:47
- a path parameter is always required: an optional express segment describes a
  different path, not an optional parameter, and the spec has no room for one;
- a route that declares only a redirect no longer receives an invented `200` with
  a schema it never answers - anything below 400 counts as documented;
- `nullable` on a schema with no usable `type` is left alone instead of spreading a
  missing value, which would have failed the route registration;
- `x-permissions` and the description read the permissions of the method over the
  wildcard ones, the way `checkPermissionsForInvocation` does at runtime;
- a nested router's paths merge into the parent per path: normalizing the keys can
  bring two distinct paths onto the same one, and replacing the map would drop the
  methods the other router documented;
- an unset `Site_Url` means no `servers` at all, rather than a Server Object with no
  url, which the spec does not allow;
- the `/api-docs` UI reads the document relative to itself, so a workspace hosted
  under ROOT_URL_PATH_PREFIX keeps its prefix;
- the `additionalItems` rename is confined to the keyword: inside `properties` and
  friends, a name is a field, not a keyword. Same mistake the discriminator strip
  made;
- the API test states the relation between the two documents instead of demanding
  that untyped routes exist, since they are meant to disappear.
The review fixes were copied across from the branch stacked on top of this one, and brought its tag map with them: this branch has no operationTags module, so the typecheck could not resolve the import.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feature Pull requests that introduces new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant