You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/api-endpoint-migration.md
+98-8Lines changed: 98 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -358,22 +358,29 @@ integrations: {
358
358
359
359
### Handling nullable types
360
360
361
-
When a field can be `null`, combine `nullable: true`with `$ref`:
361
+
Ajv does **not** allow `nullable: true` without `type`. Since `$ref` schemas don't have a `type` at the reference site, you cannot use `{ nullable: true, $ref: '...' }`. Instead, use `oneOf`with `{ type: 'null' }`:
> **Note**: `nullable: true` works fine with `type`, e.g., `{ type: 'string', nullable: true }`. The restriction only applies when combining `nullable` with `$ref` (no `type` present).
383
+
377
384
### Handling intersection types with `allOf`
378
385
379
386
When a response intersects a type with additional properties (e.g., `VideoConferenceInstructions & { providerName: string }`), use `allOf`:
@@ -440,6 +447,44 @@ This happens because `oneOf` requires **exactly one** match, but the value is bo
440
447
441
448
**Long-term fix**: Revise the core-typings to narrow `ts` to `string` (which is what MongoDB aggregation pipelines and `JSON.stringify` actually return), or adjust the AJV/typia schema generation to handle `Date | string` unions correctly (e.g., using `anyOf` instead of `oneOf`, or collapsing `Date` into `string`).
442
449
450
+
### Known Pitfall: Mapped utility types (`Nullable<>`, `Partial<>`, etc.)
451
+
452
+
Typia does **not** resolve custom mapped types when generating JSON schemas. For example, the following pattern:
Produces `avatarETag: { type: 'string' }`**without**`nullable: true`, even though the resolved type is `string | null`. This causes response validation to reject `null` values when `coerceTypes` is `false`.
464
+
465
+
**Fix**: Declare nullable fields explicitly instead of relying on mapped types:
After changing the type, rebuild core-typings (`yarn workspace @rocket.chat/core-typings run build`) to regenerate the schema.
478
+
479
+
**How to detect**: If a `$ref` schema rejects `null` values at runtime but the TypeScript type allows `null`, check if the type uses a mapped utility type. Inspect the generated schema:
The script scans for `API.v1.addRoute` and `API.default.addRoute` calls in `apps/meteor/app/api/`.
660
+
The script scans `apps/meteor/app/api/` for `API.v1.addRoute(...)` and `API.default.addRoute(...)` calls, extracting the route path, HTTP methods, file, and line number. Endpoints using this pattern lack compile-time type checking on request params and response shapes.
661
+
662
+
### `scripts/analyze-weak-types.mjs`
663
+
664
+
Analyzes `packages/rest-typings/` for "weak" types — generic types that provide little or no type safety in endpoint definitions.
665
+
666
+
```bash
667
+
# Full report grouped by endpoint
668
+
node scripts/analyze-weak-types.mjs
669
+
670
+
# JSON output for tooling/CI
671
+
node scripts/analyze-weak-types.mjs --json
672
+
673
+
# Only check AJV schema definitions (type: 'object' with no properties, etc.)
674
+
node scripts/analyze-weak-types.mjs --schema-only
675
+
676
+
# Only check TypeScript type definitions (any, Record<string, any>, etc.)
677
+
node scripts/analyze-weak-types.mjs --ts-only
678
+
```
679
+
680
+
Weak types detected:
681
+
682
+
| Pattern | Level | Risk |
683
+
|---|---|---|
684
+
|`any`, `unknown`| TypeScript | No type checking at all |
685
+
|`object` (bare) | TypeScript | Accepts any non-primitive |
686
+
|`Record<string, any>`, `Record<string, unknown>`| TypeScript | Untyped key-value bag |
0 commit comments