@lenne.tech/nest-server 11.42.14 → 11.42.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/rules/configurable-features.md +1 -0
- package/.claude/rules/testing.md +32 -13
- package/FRAMEWORK-API.md +1 -1
- package/dist/core/common/filters/mongoose-cast-error.filter.d.ts +17 -0
- package/dist/core/common/filters/mongoose-cast-error.filter.js +171 -0
- package/dist/core/common/filters/mongoose-cast-error.filter.js.map +1 -0
- package/dist/core/common/interfaces/server-options.interface.d.ts +1 -0
- package/dist/core/modules/ai/models/core-ai-budget-limit.model.d.ts +5 -1
- package/dist/core/modules/ai/models/core-ai-connection-preference.model.d.ts +5 -1
- package/dist/core/modules/ai/models/core-ai-connection.model.d.ts +5 -1
- package/dist/core/modules/ai/models/core-ai-conversation.model.d.ts +5 -1
- package/dist/core/modules/ai/models/core-ai-interaction.model.d.ts +5 -1
- package/dist/core/modules/ai/models/core-ai-mode.model.d.ts +5 -1
- package/dist/core/modules/ai/models/core-ai-prompt-hint.model.d.ts +5 -1
- package/dist/core/modules/ai/models/core-ai-prompt.model.d.ts +5 -1
- package/dist/core/modules/ai/models/core-ai-slot.model.d.ts +5 -1
- package/dist/core/modules/ai/models/core-ai-tool-grant.model.d.ts +5 -1
- package/dist/core/modules/ai/models/core-ai-tool-policy.model.d.ts +5 -1
- package/dist/core.module.js +7 -0
- package/dist/core.module.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/server/modules/file/file-info.model.d.ts +5 -1
- package/dist/server/modules/user/user.model.d.ts +5 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/docs/REQUEST-LIFECYCLE.md +29 -0
- package/docs/security-overrides.md +3 -2
- package/migration-guides/11.42.14-to-11.42.15.md +117 -0
- package/migration-guides/11.42.15-to-11.42.16.md +114 -0
- package/package.json +15 -15
- package/src/core/common/filters/mongoose-cast-error.filter.ts +310 -0
- package/src/core/common/interfaces/server-options.interface.ts +22 -0
- package/src/core/modules/better-auth/README.md +1 -1
- package/src/core/modules/hub/README.md +1 -1
- package/src/core.module.ts +13 -1
- package/src/index.ts +1 -0
|
@@ -107,6 +107,7 @@ JWT-based authentication for existing projects:
|
|
|
107
107
|
| **Security Check Interceptor** | Calls `securityCheck()` + removes secret fields |
|
|
108
108
|
| **Response Filter Interceptor** | Enforces `@Restricted()` field-level access |
|
|
109
109
|
| **Translation Interceptor** | Applies `_translations` based on `Accept-Language` |
|
|
110
|
+
| **CastError Filter** | `MongooseCastErrorFilter` (`APP_FILTER`, 11.42.16): a malformed id from a route parameter answers 404, one from the query string or an update/filter body 400, instead of an unhandled 500 (a create body raises `ValidationError` and stays a 500); a cast failure on a value the request does not contain stays a 500. See "Malformed ids: 404 / 400, not 500" below |
|
|
110
111
|
| **Secret Fields Removal** | Configurable fallback removal of password, tokens, etc. |
|
|
111
112
|
| **RequestContext** | `AsyncLocalStorage`-based context for current user in Mongoose hooks. `fromRequest` (11.42.0) marks a context created for a CLIENT operation (HTTP middleware, GraphQL WebSocket), so service-level checks such as `assertTenantRole()` tell an anonymous request apart from system work |
|
|
112
113
|
| **Query Complexity** | GraphQL query complexity analysis to prevent DoS |
|
|
@@ -1215,6 +1216,33 @@ throw accessDeniedException(currentUser);
|
|
|
1215
1216
|
See `src/core/common/exceptions/access-denied.exception.ts` and
|
|
1216
1217
|
`migration-guides/11.27.7-to-11.28.0.md`.
|
|
1217
1218
|
|
|
1219
|
+
### Malformed ids: 404 / 400, not 500 (v11.42.16+)
|
|
1220
|
+
|
|
1221
|
+
A malformed id reaches Mongoose, which throws `mongoose.Error.CastError`. That is not an
|
|
1222
|
+
`HttpException`, so it escapes `HttpExceptionLogFilter` (`@Catch(HttpException)`), and Nest used to
|
|
1223
|
+
answer **500** for what is simply "this resource does not exist". `CoreModule` registers
|
|
1224
|
+
`MongooseCastErrorFilter` as `APP_FILTER`; it decides by where the failing value came from:
|
|
1225
|
+
|
|
1226
|
+
| Value of the failed cast | REST | GraphQL |
|
|
1227
|
+
|--------------------------|------|---------|
|
|
1228
|
+
| a route parameter (`GET /users/not-an-id`) / a top-level argument (`getUser(id: …)`) | **404** `ErrorCode.RESOURCE_NOT_FOUND` | same |
|
|
1229
|
+
| the query string or the body / nested in an input object | **400** `ErrorCode.INVALID_FIELD_FORMAT [<path>]` | same |
|
|
1230
|
+
| not in the request — a broken stored id, a value computed by server code | **500**, Nest's own body and log line | unchanged (Nest rethrows) |
|
|
1231
|
+
|
|
1232
|
+
The third row is deliberate: that cast failure is a data or code defect, and answering it as a client
|
|
1233
|
+
error would hide it from monitoring. The Mongoose message never reaches the client — it names the
|
|
1234
|
+
model. Opt out with `security.mongooseCastErrorFilter: false`.
|
|
1235
|
+
|
|
1236
|
+
Mongoose throws `CastError` only while casting a **query or an update** — `findById`, filters,
|
|
1237
|
+
`findByIdAndUpdate` / `updateOne` (the path `CrudService.update()` takes). Two neighbours are not
|
|
1238
|
+
covered and stay a 500:
|
|
1239
|
+
|
|
1240
|
+
- a malformed id in a document being **created or saved** (`save()`, `Model.create()`, `insertMany()`
|
|
1241
|
+
— the path `CrudService.create()` takes) arrives as a `ValidationError` wrapping the CastError;
|
|
1242
|
+
validate reference ids in the input (`validator: () => [IsMongoId()]` on the `@UnifiedField`);
|
|
1243
|
+
- a `BSONError` from `new Types.ObjectId(bad)` in service code carries no value to classify; validate
|
|
1244
|
+
such ids in the service, as `CoreFileService.isMalformedFileId()` does.
|
|
1245
|
+
|
|
1218
1246
|
### Depth-Based Optimization (v11.23.0+)
|
|
1219
1247
|
|
|
1220
1248
|
When `process()` is called from within another `process()` call (service cascades like A.create → B.create → C.create), steps 4–6 are **conditionally skipped** on inner calls to avoid redundant work:
|
|
@@ -1643,6 +1671,7 @@ All security features are configured in `config.env.ts` under the `security` key
|
|
|
1643
1671
|
| `security.checkSecurityInterceptor` | `boolean \| object` | `true` | Enable securityCheck() calls |
|
|
1644
1672
|
| `security.mapAndValidatePipe` | `boolean \| object` | `true` | Enable input validation |
|
|
1645
1673
|
| `security.mapAndValidatePipe.nonWhitelistedFields` | `'strip' \| 'error' \| false` | `'strip'` | Whitelist behavior |
|
|
1674
|
+
| `security.mongooseCastErrorFilter` | `boolean` | `true` | Malformed request ids answer 404 / 400 instead of 500 |
|
|
1646
1675
|
|
|
1647
1676
|
### Safety Net — Mongoose Plugins
|
|
1648
1677
|
|
|
@@ -64,13 +64,14 @@ overrides:
|
|
|
64
64
|
'multer@>=2.0.0 <2.4.0': '2.4.0'
|
|
65
65
|
|
|
66
66
|
# @nestjs/graphql 13.4.5 exact-pins @graphql-tools/utils@12.0.0 — GHSA-7mx3-vvmw-hjmv (high, patched >=12.0.1).
|
|
67
|
-
# Target the newest 12.x, so the caret requesters (@graphql-tools/schema / merge) are not held back
|
|
67
|
+
# Target the newest 12.x, so the caret requesters (@graphql-tools/schema / merge) are not held back —
|
|
68
|
+
# @graphql-tools/schema 10.1.5 requests ^12.1.0, so a lower target leaves a second copy in the tree.
|
|
68
69
|
# 12.0.2+ requires Node >=22.15 via @whatwg-node/promise-helpers@2 — the floor this framework declares
|
|
69
70
|
# since 11.42.10. On an older Node, take 12.0.1 instead.
|
|
70
71
|
# Does NOT reach a utils 11.x pulled in by an older @graphql-tools/schema 10.0.x — refresh that one instead:
|
|
71
72
|
# pnpm update --depth Infinity @graphql-tools/schema @graphql-tools/merge
|
|
72
73
|
# Remove once @nestjs/graphql pins >=12.0.1 in the major you use.
|
|
73
|
-
'@graphql-tools/utils@>=12.0.0 <12.0
|
|
74
|
+
'@graphql-tools/utils@>=12.0.0 <12.1.0': '12.1.0'
|
|
74
75
|
```
|
|
75
76
|
|
|
76
77
|
### Retired: `@hono/node-server` (removed 2026-08-22, nest-server 11.36.1)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Migration Guide: 11.42.14 → 11.42.15
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
| Category | Details |
|
|
6
|
+
| -------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| **Bugfixes** | No framework code changes; security release of the runtime dependency `undici` (§3) |
|
|
8
|
+
| **New Features** | None |
|
|
9
|
+
| **Framework API** | Unchanged — no new exports, no changed signatures |
|
|
10
|
+
| **Dependencies** | `mongoose` 9.10.4 → 9.11.2 and `mongodb` 7.6.0 → 7.7.0 (both `dependencies`, raised together, §1); **`undici` 7.30.0 → 7.30.1 (security release, §3)**; `nodemailer` 10.1.0 → 10.1.2; `@getbrevo/brevo` 6.0.3 → 6.2.0; overrides `@graphql-tools/utils` → 12.0.4, `undici` → 7.30.1, `qs` → 6.16.1 |
|
|
11
|
+
| **Breaking Changes** | None |
|
|
12
|
+
| **Migration Effort** | Low, but **one step is required**: a project that keeps `mongodb` in `devDependencies` (the starter default) MUST raise it to 7.7.0 — by hand, or with the starter's new update script — or sign-in fails with 401 (§1). Typed `lean()` / `bulkWrite()` code may need a type adjustment (§2) |
|
|
13
|
+
|
|
14
|
+
## Quick Migration
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm run update # starter-based projects: raises every pin the framework raised
|
|
18
|
+
pnpm why mongodb # must show ONE version: 7.7.0
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
If `pnpm why mongodb` lists 7.6.0 next to 7.7.0, raise the project's own `mongodb` entry to `7.7.0` (§1). If your
|
|
22
|
+
project has its own `undici` override, raise it to 7.30.1 (§3) — `pnpm audit` does not flag this one yet.
|
|
23
|
+
|
|
24
|
+
Vendor-mode projects pick up the core with `/lt-dev:backend:update-nest-server-core`; raise `mongoose` and `mongodb`
|
|
25
|
+
in the project's `package.json` to the versions above in the same step.
|
|
26
|
+
|
|
27
|
+
## 1. mongoose 9.11 and mongodb 7.7 move together
|
|
28
|
+
|
|
29
|
+
mongoose 9.11.x requires `mongodb ~7.7`, so both are raised in this release. nest-server declares `mongodb` under
|
|
30
|
+
`dependencies`. nest-server-starter keeps it under `devDependencies` — and that pin is **not test-only**: Better-Auth's
|
|
31
|
+
MongoDB adapter (`@better-auth/mongo-adapter`, used by nest-server's IAM module) resolves its `mongodb` peer from the
|
|
32
|
+
project's own `mongodb` entry, in the production image too.
|
|
33
|
+
|
|
34
|
+
Until this release, `pnpm run update` (the starter's `extras/sync-packages.mjs`) raised a pin only when the framework
|
|
35
|
+
declared it **in the same section**. A project with `mongodb` in `devDependencies` therefore stayed on 7.6.0 while the
|
|
36
|
+
framework's mongoose brought 7.7.0: two driver copies. Where the project's lockfile still holds the older `bson` for
|
|
37
|
+
the old driver (any lockfile not refreshed since bson 7.3), there are two `bson` copies as well. The adapter checks ids
|
|
38
|
+
with `instanceof ObjectId` against ITS driver's bson, the ids come from the framework's — so the check fails, the
|
|
39
|
+
adapter throws `MongoAdapterError: Invalid id value`, and authenticated requests answer **401**. With a single shared
|
|
40
|
+
bson it stays a typing problem in tests (`Db` / `MongoClient` from the test helpers no longer match the project's own
|
|
41
|
+
import). Neither is acceptable, and which one a project gets depends on its lockfile history, so raise the pin.
|
|
42
|
+
|
|
43
|
+
The starter's update script now raises a package the framework **ships** (`dependencies`) in whichever section the
|
|
44
|
+
project keeps it. A package the framework only develops and tests with (`devDependencies`) still raises only the
|
|
45
|
+
project's own `devDependencies` — never a runtime pin. That keeps the better-auth trio where it belongs: the framework
|
|
46
|
+
holds it as devDependencies (its test versions, with a peer range as the contract), the project holds it as
|
|
47
|
+
dependencies and owns that version, because its api and app must resolve the same better-auth. The rule lives in
|
|
48
|
+
`extras/align-package-versions.mjs`, and nest-server's consumer gate (`pnpm run check:consumer`) applies the identical
|
|
49
|
+
rule before every release.
|
|
50
|
+
|
|
51
|
+
**What to do:**
|
|
52
|
+
|
|
53
|
+
- **Your project still has the old `extras/sync-packages.mjs`:** raise `mongodb` to `7.7.0` by hand (also
|
|
54
|
+
`json-to-graphql-query`, if you keep it in `devDependencies` and it lags), or copy `extras/sync-packages.mjs` and
|
|
55
|
+
`extras/align-package-versions.mjs` from nest-server-starter. **This step is required** — skipping it breaks sign-in.
|
|
56
|
+
- **Your project has `mongodb` in `dependencies`:** `pnpm run update` already raised it; nothing to do.
|
|
57
|
+
- **Check either way:** `pnpm why mongodb` must list exactly one version.
|
|
58
|
+
|
|
59
|
+
## 2. mongoose 9.11 type changes
|
|
60
|
+
|
|
61
|
+
No runtime behaviour your code relies on changed, but two typing changes can surface in a project's own code:
|
|
62
|
+
|
|
63
|
+
- `lean()` now passes its result type into the query, so a `lean<T>()` result is narrowed to `T`. Code that assigned
|
|
64
|
+
the result to an incompatible type now gets a compile error instead of a silent mismatch.
|
|
65
|
+
- `UpdateOneModel` / `UpdateManyModel` (`bulkWrite()` operations) are typed like `UpdateQuery`. An update document that
|
|
66
|
+
was accepted by the looser type may now need its operators spelled out (`$set`, `$push`, …).
|
|
67
|
+
|
|
68
|
+
Runtime fixes that come along (no action needed): validators on document arrays under nested paths no longer run
|
|
69
|
+
twice, `bulkWrite()` casts array filter values, cursors await driver cleanup on destroy. The mongodb 7.7 driver
|
|
70
|
+
recovers from a failed OIDC token fetch instead of failing every later operation on that client.
|
|
71
|
+
|
|
72
|
+
## 3. undici 7.30.1 is a security release
|
|
73
|
+
|
|
74
|
+
undici 7.30.1 fixes four high and four medium advisories (GHSA-qrxm-fqhp-jwvm, GHSA-2m5v-pch6-74hx,
|
|
75
|
+
GHSA-4w7w-5xrc-9h26, GHSA-xjj6-f33q-929c high; GHSA-55wc-3pg8-jfw6, GHSA-f72v-6w45-q472, GHSA-4qv8-2p9j-2685,
|
|
76
|
+
GHSA-9fm3-97px-rjf6 medium). They were published as repository advisories, so **`pnpm audit` does not report them
|
|
77
|
+
yet** — a green audit says nothing about this release. nest-server uses undici at runtime for `outboundFetch()` (the
|
|
78
|
+
SSRF-guarded fetch for user-entered URLs), and one of the fixes concerns function-valued Agent options, which that
|
|
79
|
+
helper's guarded connector is.
|
|
80
|
+
|
|
81
|
+
**What to do:**
|
|
82
|
+
|
|
83
|
+
- **Nothing for nest-server's own dependency** — `pnpm run update` raises it.
|
|
84
|
+
- **Your project carries its own `undici` override** (starter-derived projects do, for the
|
|
85
|
+
`@compodoc/compodoc > cheerio > undici` path): raise key and target together, e.g.
|
|
86
|
+
`'undici@>=7.0.0 <7.30.0': 7.30.0` → `'undici@>=7.0.0 <7.30.1': 7.30.1`. The old entry would otherwise keep that path
|
|
87
|
+
on the vulnerable 7.30.0, because cheerio's `^7.19.0` intersects the old key.
|
|
88
|
+
- **Check:** `pnpm why undici` lists only 7.30.1.
|
|
89
|
+
|
|
90
|
+
Also raised in the same way (no advisory, removes a hold-back): `qs` override `<6.16.0` → `<6.16.1` (6.16.1), and
|
|
91
|
+
`nodemailer` 10.1.2, which strips credentials on a cross-origin redirect.
|
|
92
|
+
|
|
93
|
+
## Compatibility Notes
|
|
94
|
+
|
|
95
|
+
| Pattern | Status |
|
|
96
|
+
| ------- | ------ |
|
|
97
|
+
| `mongodb` in `dependencies` of the project | Raised by `pnpm run update` as before |
|
|
98
|
+
| `mongodb` in `devDependencies` of the project (starter default) | Raised only by the new update script — otherwise raise by hand, **required** (§1) |
|
|
99
|
+
| better-auth / `@better-auth/*` in the project's `dependencies` | Never raised from the framework's devDependencies — the project owns that version, as before |
|
|
100
|
+
| `lean<T>()` with an explicit result type | May need a type adjustment (§2) |
|
|
101
|
+
| `bulkWrite()` with typed `updateOne` / `updateMany` operations | May need operators spelled out (§2) |
|
|
102
|
+
| Routes with `@Roles()` + `@UseGuards(AuthGuard(BETTER_AUTH))` | Unchanged. nest-server-starter dropped these redundant guards from its `UserController`; removing them in your project is optional |
|
|
103
|
+
|
|
104
|
+
## Troubleshooting
|
|
105
|
+
|
|
106
|
+
**Sign-in or every authenticated request answers 401, the log shows `MongoAdapterError: Invalid id value`**
|
|
107
|
+
Two mongodb (and bson) versions are installed, and Better-Auth's MongoDB adapter uses the project's older one.
|
|
108
|
+
`pnpm why mongodb` shows both; raise the project's own `mongodb` entry to 7.7.0, run `pnpm install`, and rebuild the
|
|
109
|
+
image (§1).
|
|
110
|
+
|
|
111
|
+
**Type errors around `Db`, `MongoClient` or `Collection` in tests after the update**
|
|
112
|
+
Same cause, same fix: two mongodb versions are installed. Raise the project's own entry to 7.7.0 and run
|
|
113
|
+
`pnpm install`.
|
|
114
|
+
|
|
115
|
+
## Module Documentation
|
|
116
|
+
|
|
117
|
+
- [nest-server-starter `extras/align-package-versions.mjs`](https://github.com/lenneTech/nest-server-starter/blob/main/extras/align-package-versions.mjs)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Migration Guide: 11.42.15 → 11.42.16
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
| Category | Details |
|
|
6
|
+
| -------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| **Bugfixes** | A malformed id in a route parameter answers **404** instead of **500**; one in the query string or an update body **400** (§1) |
|
|
8
|
+
| **New Features** | `MongooseCastErrorFilter`, registered automatically; opt-out `security.mongooseCastErrorFilter: false` (§1) |
|
|
9
|
+
| **Framework API** | New exports: `MongooseCastErrorFilter`, `classifyHttpCastError()`, `classifyGraphQlCastError()`, `castErrorCandidates()`, `containsCastValue()`, type `CastErrorOrigin`. No changed signatures |
|
|
10
|
+
| **Dependencies** | Development tooling only: `vitest` / `@vitest/coverage-v8` 4.1.11 → 4.1.12 (security, §2), `oxfmt` 0.72.0 → 0.73.0; override `@graphql-tools/utils` → 12.1.0 (§2). Runtime dependencies and peer ranges unchanged |
|
|
11
|
+
| **Breaking Changes** | None. Status codes change from 500 to 404 / 400 for requests that were already failing (§1) |
|
|
12
|
+
| **Migration Effort** | None for most projects. Check tests or clients that expected a 500 for a malformed id (§1) |
|
|
13
|
+
|
|
14
|
+
## Quick Migration
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm update @lenne.tech/nest-server
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Vendor-mode projects pick it up with the core update. No code or configuration change is required — the filter is
|
|
21
|
+
registered by `CoreModule`, so neither `main.ts` nor test setups built with `Test.createTestingModule()` need a new
|
|
22
|
+
line.
|
|
23
|
+
|
|
24
|
+
## 1. Malformed ids answer 404 / 400 instead of 500
|
|
25
|
+
|
|
26
|
+
A malformed id in a route parameter (`GET /users/not-an-id`, `/ai/connections/abc`) reached Mongoose, which throws
|
|
27
|
+
`mongoose.Error.CastError`. That is not an `HttpException`, so it escaped `HttpExceptionLogFilter`
|
|
28
|
+
(`@Catch(HttpException)`) and Nest answered **500 Internal server error** for what is simply "this resource does not
|
|
29
|
+
exist". In a typical project that affected every `:id` route, including the framework's own `/users/:id` and the AI
|
|
30
|
+
module's routes.
|
|
31
|
+
|
|
32
|
+
`CoreModule` now registers `MongooseCastErrorFilter` as `APP_FILTER`. It decides by where the value that failed to
|
|
33
|
+
cast came from:
|
|
34
|
+
|
|
35
|
+
| Value of the failed cast | REST | GraphQL |
|
|
36
|
+
| ------------------------ | ---- | ------- |
|
|
37
|
+
| a route parameter / a top-level argument (`getUser(id: …)`) | **404** `#LTNS_0400: Resource not found` | same |
|
|
38
|
+
| the query string or an update / filter body / a value nested in an input | **400** `#LTNS_0302: Invalid field format [<path>]` | same |
|
|
39
|
+
| not in the request (a broken stored id, a value computed by server code) | **500**, unchanged — Nest's body, logged as an error | unchanged |
|
|
40
|
+
|
|
41
|
+
The third row is deliberate: a cast failure on a value the request does not contain is a data or code defect, and
|
|
42
|
+
answering it as a client error would hide it from monitoring. The Mongoose message is never sent to the client — it
|
|
43
|
+
names the model. REST bodies have the same shape as every other error `HttpExceptionLogFilter` answers.
|
|
44
|
+
|
|
45
|
+
**What to check:**
|
|
46
|
+
|
|
47
|
+
- **A test or client expected 500 for a malformed id:** it now gets 404 (route parameter) or 400 (query / body).
|
|
48
|
+
A well-formed id that matches nothing keeps answering 404 as before, so 404 now means the same for both.
|
|
49
|
+
- **A project filter already handled `CastError`:** a catch-all filter registered with `app.useGlobalFilters()` is
|
|
50
|
+
consulted before this one and keeps winning. One registered as `APP_FILTER` in the project's root module is
|
|
51
|
+
consulted after it — set `security.mongooseCastErrorFilter: false` if your own filter must see every `CastError`
|
|
52
|
+
(for example a Sentry filter that reports them).
|
|
53
|
+
- **You want the previous behaviour:** `security.mongooseCastErrorFilter: false` restores the 500.
|
|
54
|
+
|
|
55
|
+
**Not covered — both stay a 500:**
|
|
56
|
+
|
|
57
|
+
- A malformed id in a document being **created** (`save()`, `Model.create()`, `insertMany()` — the path
|
|
58
|
+
`CrudService.create()` takes). Mongoose reports that as a `ValidationError` wrapping the `CastError`. Validate
|
|
59
|
+
reference ids in the input instead:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { IsMongoId } from 'class-validator';
|
|
63
|
+
|
|
64
|
+
@UnifiedField({ isOptional: true, type: () => String, validator: () => [IsMongoId()] })
|
|
65
|
+
owner?: string = undefined;
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
- A `BSONError` from `new Types.ObjectId(bad)` in service code. It carries no value to classify; check the id
|
|
69
|
+
before converting it, as `CoreFileService.isMalformedFileId()` does.
|
|
70
|
+
|
|
71
|
+
## 2. Development tooling and the `@graphql-tools/utils` override
|
|
72
|
+
|
|
73
|
+
Nothing here reaches the published package's runtime dependencies. Worth mirroring in your own project:
|
|
74
|
+
|
|
75
|
+
- **`vitest` and `@vitest/coverage-v8` 4.1.12** fix two `@vitest/mocker` advisories published on 2026-10-16
|
|
76
|
+
(GHSA-qxg6-89mg-rqv8, GHSA-xp26-3454-mjgp, both medium). Development tooling only. `pnpm audit` may not list them
|
|
77
|
+
yet, so raise both together without waiting for it: `@vitest/coverage-v8` peer-requires the exact vitest version.
|
|
78
|
+
- **`@graphql-tools/utils` override:** if your project carries its own entry for GHSA-7mx3-vvmw-hjmv (overrides do
|
|
79
|
+
not reach consumers, so many do), raise it:
|
|
80
|
+
|
|
81
|
+
```yaml
|
|
82
|
+
# pnpm-workspace.yaml
|
|
83
|
+
overrides:
|
|
84
|
+
'@graphql-tools/utils@>=12.0.0 <12.1.0': '12.1.0' # was: '<12.0.3': '12.0.3' / '<12.0.4': '12.0.4'
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The old target still clears the advisory, but `@graphql-tools/schema` 10.1.5 (pulled in by `@apollo/server`)
|
|
88
|
+
requests `^12.1.0`, so a lower target leaves two copies of `@graphql-tools/utils` in the tree.
|
|
89
|
+
See [`docs/security-overrides.md`](../docs/security-overrides.md).
|
|
90
|
+
|
|
91
|
+
## Compatibility Notes
|
|
92
|
+
|
|
93
|
+
| Pattern | Status |
|
|
94
|
+
| ------- | ------ |
|
|
95
|
+
| `main.ts` with `app.useGlobalFilters(new HttpExceptionLogFilter())` | Unchanged; both filters coexist (they catch different classes) |
|
|
96
|
+
| A project catch-all filter via `app.useGlobalFilters()` | Unchanged; it still sees every `CastError` |
|
|
97
|
+
| A project catch-all filter as `APP_FILTER` in the root module | No longer sees `CastError` — opt out if it must (§1) |
|
|
98
|
+
| Tests built with `Test.createTestingModule({ imports: [ServerModule] })` | Get the filter automatically |
|
|
99
|
+
| `security.mongooseCastErrorFilter: false` | Previous behaviour (500) |
|
|
100
|
+
|
|
101
|
+
## Troubleshooting
|
|
102
|
+
|
|
103
|
+
**A malformed id still answers 500**
|
|
104
|
+
Check where it fails. A create path raises `ValidationError` (see "Not covered" above); a `new Types.ObjectId(bad)` in
|
|
105
|
+
service code raises `BSONError`; a value from a header or from stored data is not in the request and stays a 500 on
|
|
106
|
+
purpose. The server log names the cast at debug level (`MongooseCastErrorFilter`) when the filter answered 404 / 400.
|
|
107
|
+
|
|
108
|
+
**A 400 names a field the client did not send**
|
|
109
|
+
The path in brackets is the schema path Mongoose failed to cast. For a filter on `id` it reads `[_id]`.
|
|
110
|
+
|
|
111
|
+
## Module Documentation
|
|
112
|
+
|
|
113
|
+
- [Request lifecycle](../docs/REQUEST-LIFECYCLE.md) — "Malformed ids: 404 / 400, not 500"
|
|
114
|
+
- Implementation: `src/core/common/filters/mongoose-cast-error.filter.ts`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "11.42.
|
|
3
|
+
"version": "11.42.16",
|
|
4
4
|
"description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"node",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"dependencies": {
|
|
92
92
|
"@apollo/server": "5.5.1",
|
|
93
93
|
"@as-integrations/express5": "1.1.2",
|
|
94
|
-
"@getbrevo/brevo": "6.0
|
|
94
|
+
"@getbrevo/brevo": "6.2.0",
|
|
95
95
|
"@modelcontextprotocol/sdk": "1.32.1",
|
|
96
96
|
"@nestjs/apollo": "13.4.5",
|
|
97
97
|
"@nestjs/common": "11.2.7",
|
|
@@ -125,11 +125,11 @@
|
|
|
125
125
|
"js-sha256": "1.0.0",
|
|
126
126
|
"json-to-graphql-query": "2.3.0",
|
|
127
127
|
"lodash": "4.18.1",
|
|
128
|
-
"mongodb": "7.
|
|
129
|
-
"mongoose": "9.
|
|
128
|
+
"mongodb": "7.7.0",
|
|
129
|
+
"mongoose": "9.11.2",
|
|
130
130
|
"multer": "2.4.0",
|
|
131
131
|
"node-mailjet": "6.0.11",
|
|
132
|
-
"nodemailer": "10.1.
|
|
132
|
+
"nodemailer": "10.1.2",
|
|
133
133
|
"passport": "0.7.0",
|
|
134
134
|
"passport-jwt": "4.0.1",
|
|
135
135
|
"reflect-metadata": "0.2.2",
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"rxjs": "7.8.2",
|
|
138
138
|
"supertest": "7.3.1",
|
|
139
139
|
"ts-morph": "28.0.0",
|
|
140
|
-
"undici": "7.30.
|
|
140
|
+
"undici": "7.30.1",
|
|
141
141
|
"ws": "8.21.3",
|
|
142
142
|
"yuml-diagram": "1.2.0"
|
|
143
143
|
},
|
|
@@ -182,9 +182,9 @@
|
|
|
182
182
|
}
|
|
183
183
|
},
|
|
184
184
|
"devDependencies": {
|
|
185
|
-
"@aws-sdk/client-s3": "3.
|
|
186
|
-
"@aws-sdk/lib-storage": "3.
|
|
187
|
-
"@aws-sdk/s3-request-presigner": "3.
|
|
185
|
+
"@aws-sdk/client-s3": "3.1152.0",
|
|
186
|
+
"@aws-sdk/lib-storage": "3.1152.0",
|
|
187
|
+
"@aws-sdk/s3-request-presigner": "3.1152.0",
|
|
188
188
|
"@better-auth/core": "1.7.7",
|
|
189
189
|
"@better-auth/passkey": "1.7.7",
|
|
190
190
|
"@compodoc/compodoc": "2.0.0",
|
|
@@ -202,18 +202,18 @@
|
|
|
202
202
|
"@types/multer": "2.3.0",
|
|
203
203
|
"@types/node": "26.6.5",
|
|
204
204
|
"@types/passport": "1.0.17",
|
|
205
|
-
"@vitest/coverage-v8": "4.1.
|
|
205
|
+
"@vitest/coverage-v8": "4.1.12",
|
|
206
206
|
"better-auth": "1.7.7",
|
|
207
|
-
"bullmq": "6.3.
|
|
207
|
+
"bullmq": "6.3.15",
|
|
208
208
|
"cross-env": "10.1.0",
|
|
209
209
|
"ioredis": "6.0.0",
|
|
210
210
|
"nodemon": "3.1.14",
|
|
211
211
|
"npm-watch": "0.13.0",
|
|
212
212
|
"otpauth": "9.5.2",
|
|
213
|
-
"oxfmt": "0.
|
|
214
|
-
"oxlint": "1.
|
|
213
|
+
"oxfmt": "0.73.0",
|
|
214
|
+
"oxlint": "1.88.0",
|
|
215
215
|
"rimraf": "6.1.3",
|
|
216
|
-
"smtp-server": "3.19.
|
|
216
|
+
"smtp-server": "3.19.23",
|
|
217
217
|
"ts-node": "10.9.2",
|
|
218
218
|
"tsconfig-paths": "4.2.0",
|
|
219
219
|
"tsx": "4.23.15",
|
|
@@ -222,7 +222,7 @@
|
|
|
222
222
|
"unplugin-swc": "2.0.0",
|
|
223
223
|
"vite": "8.3.4",
|
|
224
224
|
"vite-plugin-node": "8.0.0",
|
|
225
|
-
"vitest": "4.1.
|
|
225
|
+
"vitest": "4.1.12"
|
|
226
226
|
},
|
|
227
227
|
"main": "dist/index.js",
|
|
228
228
|
"types": "dist/index.d.ts",
|