@lenne.tech/nest-server 11.42.9 → 11.42.11
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/testing.md +10 -8
- package/CLAUDE.md +1 -1
- package/FRAMEWORK-API.md +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/docs/security-overrides.md +6 -5
- package/migration-guides/11.27.2-to-11.27.3.md +4 -2
- package/migration-guides/11.36.3-to-11.36.4.md +12 -7
- package/migration-guides/11.42.10-to-11.42.11.md +160 -0
- package/migration-guides/11.42.9-to-11.42.10.md +111 -0
- package/package.json +14 -15
|
@@ -18,7 +18,7 @@ used to **exact-pin**, to a vulnerable version:
|
|
|
18
18
|
|---------|----------|------------------------------------------|
|
|
19
19
|
| `ws` | [GHSA-96hv-2xvq-fx4p](https://github.com/advisories/GHSA-96hv-2xvq-fx4p) — high: memory-exhaustion DoS + uninitialized memory disclosure. Patched `>=8.21.0` | Older `@nestjs/graphql` releases declare `"ws": "8.20.1"` — an **exact pin**, not a caret. 13.4.5, the version this framework declares, pins `8.21.3` |
|
|
20
20
|
| `js-yaml` | [GHSA-pm4m-ph32-ghv5](https://github.com/advisories/GHSA-pm4m-ph32-ghv5) — high: exponential parsing time in flow collections (DoS), patched `>=5.2.2`; [GHSA-r3ph-w7gj-g6xm](https://github.com/advisories/GHSA-r3ph-w7gj-g6xm) — moderate: `maxTotalMergeKeys` does not bound CPU use for empty merge sources, covers `<=5.4.0`, patched `>=5.4.1` (published 2026-09-29) | `@nestjs/swagger` declares js-yaml as an **exact pin**, the same shape as the `ws` case: older releases `5.2.1`, 11.4.7 — the version this framework declares, and the newest 11.x — `5.3.0`. No swagger update reaches the fix, so **this entry is load-bearing again** |
|
|
21
|
-
| `@graphql-tools/utils` | [GHSA-7mx3-vvmw-hjmv](https://github.com/advisories/GHSA-7mx3-vvmw-hjmv) — high: prototype pollution in `mergeDeep`, which runs while the GraphQL schema is assembled. Covers `<=12.0.0`, patched `>=12.0.1` (added 2026-10-06) | `@nestjs/graphql` 13.4.5 — the version this framework declares, and the newest 13.x — declares `"@graphql-tools/utils": "12.0.0"`, an **exact pin**. Only `@nestjs/graphql` 14.x moves it, so **this entry is load-bearing**. `@apollo/server` reaches it too, through `@graphql-tools/schema` / `merge` — and in a lockfile that still holds schema 10.0.x (resolved before 2026-08-12), as **utils 11.x**: vulnerable too, with no 11.x fix, and outside the override key. Lift it with `pnpm update --depth Infinity @graphql-tools/schema @graphql-tools/merge`; the current releases request utils `^12.0.3`, which needs Node >=22.15 |
|
|
21
|
+
| `@graphql-tools/utils` | [GHSA-7mx3-vvmw-hjmv](https://github.com/advisories/GHSA-7mx3-vvmw-hjmv) — high: prototype pollution in `mergeDeep`, which runs while the GraphQL schema is assembled. Covers `<=12.0.0`, patched `>=12.0.1` (added 2026-10-06) | `@nestjs/graphql` 13.4.5 — the version this framework declares, and the newest 13.x — declares `"@graphql-tools/utils": "12.0.0"`, an **exact pin**. Only `@nestjs/graphql` 14.x moves it, so **this entry is load-bearing**. `@apollo/server` reaches it too, through `@graphql-tools/schema` / `merge` — and in a lockfile that still holds schema 10.0.x (resolved before 2026-08-12), as **utils 11.x**: vulnerable too, with no 11.x fix, and outside the override key. Lift it with `pnpm update --depth Infinity @graphql-tools/schema @graphql-tools/merge`; the current releases request utils `^12.0.3`, which needs Node >=22.15 — the framework's own floor since 11.42.10, which is why the snippet below targets 12.0.3 |
|
|
22
22
|
| `multer` | [GHSA-wc9g-mqfw-jrwm](https://github.com/advisories/GHSA-wc9g-mqfw-jrwm), [GHSA-535w-7cp7-47q4](https://github.com/advisories/GHSA-535w-7cp7-47q4), [GHSA-qfvm-cv95-jqjf](https://github.com/advisories/GHSA-qfvm-cv95-jqjf) — high: DoS via crafted multipart input; [GHSA-qvfw-j98x-7q72](https://github.com/advisories/GHSA-qvfw-j98x-7q72) — low: file size limit bypass. Patched `>=2.3.0` | `@nestjs/platform-express` up to 11.2.5 declares `"multer": "2.2.0"` — an **exact pin**. A direct `multer` dependency does not move it: you get both copies, and FileInterceptor uses the vulnerable one. 11.2.6, which this framework declared from 11.41.4, pins `2.4.0`, and so does 11.2.7, declared since 11.41.7 |
|
|
23
23
|
|
|
24
24
|
**Status since 11.42.4:** `@graphql-tools/utils` joins `js-yaml` as load-bearing — no `@nestjs/graphql`
|
|
@@ -64,12 +64,13 @@ 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
|
|
68
|
-
#
|
|
67
|
+
# Target the newest 12.x, so the caret requesters (@graphql-tools/schema / merge) are not held back.
|
|
68
|
+
# 12.0.2+ requires Node >=22.15 via @whatwg-node/promise-helpers@2 — the floor this framework declares
|
|
69
|
+
# since 11.42.10. On an older Node, take 12.0.1 instead.
|
|
69
70
|
# Does NOT reach a utils 11.x pulled in by an older @graphql-tools/schema 10.0.x — refresh that one instead:
|
|
70
|
-
# pnpm update --depth Infinity @graphql-tools/schema @graphql-tools/merge
|
|
71
|
+
# pnpm update --depth Infinity @graphql-tools/schema @graphql-tools/merge
|
|
71
72
|
# Remove once @nestjs/graphql pins >=12.0.1 in the major you use.
|
|
72
|
-
'@graphql-tools/utils@>=12.0.0 <12.0.
|
|
73
|
+
'@graphql-tools/utils@>=12.0.0 <12.0.3': '12.0.3'
|
|
73
74
|
```
|
|
74
75
|
|
|
75
76
|
### Retired: `@hono/node-server` (removed 2026-08-22, nest-server 11.36.1)
|
|
@@ -155,8 +155,10 @@ some projects copied `scripts/check.mjs` from 11.27.1+:
|
|
|
155
155
|
no longer wipe each other's users/sessions mid-flight. A new reporter
|
|
156
156
|
(`tests/db-lifecycle.reporter.ts`) drops the DB after a successful run and
|
|
157
157
|
collects stale leftovers; after a failed run the DB is kept for debugging
|
|
158
|
-
until the next successful run. An externally set `
|
|
159
|
-
the previous behavior.
|
|
158
|
+
until the next successful run. An externally set `NSC__MONGOOSE__URI` (CI)
|
|
159
|
+
keeps the previous behavior. (This line originally said `MONGODB_URI`, the
|
|
160
|
+
variable the framework's own test setup reads; a starter-derived project's
|
|
161
|
+
`tests/global-setup.ts` reads `NSC__MONGOOSE__URI`.)
|
|
160
162
|
|
|
161
163
|
---
|
|
162
164
|
|
|
@@ -35,10 +35,15 @@ fix reaches an existing project.
|
|
|
35
35
|
1. Your project's slug contains `ci`, `test`, `e2e` or `acctest` **as a substring** — including
|
|
36
36
|
inside an ordinary word: `ci` hides in so**ci**al, spe**ci**al, finan**ci**al, invoi**ci**ng,
|
|
37
37
|
pri**ci**ng, muni**ci**pal; `test` hides in la**test**, con**test**, **test**imonials.
|
|
38
|
-
2. You use `lt dev up`, which exports `
|
|
39
|
-
database.
|
|
38
|
+
2. You use `lt dev up`, which exports `NSC__MONGOOSE__URI` pointing at `<slug>-local` — your
|
|
39
|
+
**development** database, and the variable your `tests/global-setup.ts` drops when it is set.
|
|
40
40
|
3. You started the e2e suite from that same shell.
|
|
41
41
|
|
|
42
|
+
> **Correction (11.42.x):** earlier versions of this guide named `MONGODB_URI` throughout. That is
|
|
43
|
+
> the variable the framework's OWN test setup reads; `lt dev` never sets it. A starter-derived
|
|
44
|
+
> project's `tests/global-setup.ts` reads `NSC__MONGOOSE__URI`, which `lt dev` does export — so
|
|
45
|
+
> the steps below are right for your project, only the variable name was wrong.
|
|
46
|
+
|
|
42
47
|
Then `tests/global-setup.ts` dropped that database. The guard meant to prevent exactly this accepted
|
|
43
48
|
it, because it matched the marker anywhere in the name rather than as a delimited segment.
|
|
44
49
|
|
|
@@ -82,7 +87,7 @@ cannot:
|
|
|
82
87
|
|
|
83
88
|
**A second guard for the one drop site that has no other condition.** The startup sweep and the
|
|
84
89
|
post-run collection both additionally require `isStaleTestDb()` — the name must belong to your own
|
|
85
|
-
base. The externally-supplied-`
|
|
90
|
+
base. The externally-supplied-`NSC__MONGOOSE__URI` branch has no such backstop, and a project slug may
|
|
86
91
|
legitimately carry a marker as a *whole word*: `ci` is the ordinary German abbreviation for
|
|
87
92
|
*Corporate Identity*, `test` a product noun for an exam. `ci-portal-local` passes the segment rule.
|
|
88
93
|
|
|
@@ -100,7 +105,7 @@ Then use `isDroppableTestDb(db.databaseName)` in place of `SAFE_TEST_DB_PATTERN.
|
|
|
100
105
|
database into a leaked one.
|
|
101
106
|
|
|
102
107
|
**Refuse a URI that names no database.** `mongodb://127.0.0.1` makes the driver fall back to its
|
|
103
|
-
default database, `test` — a name the guard accepts, so a truncated `
|
|
108
|
+
default database, `test` — a name the guard accepts, so a truncated `NSC__MONGOOSE__URI` dropped the
|
|
104
109
|
server's `test` database instead of failing. Note that this needs the `splitMongoUri()` fix too: the
|
|
105
110
|
previous greedy form reported the **host** as the database name for such a URI, so the check could
|
|
106
111
|
never fire.
|
|
@@ -125,7 +130,7 @@ refusal list *is* the specification, and reverting the anchoring turns 13 cases
|
|
|
125
130
|
|---------|--------|
|
|
126
131
|
| npm-mode projects | Unaffected by the package update; apply §1 to your own `tests/` |
|
|
127
132
|
| Vendor-mode projects | Same — `tests/` is outside the vendor file set |
|
|
128
|
-
| CI pipelines that pin `
|
|
133
|
+
| CI pipelines that pin `NSC__MONGOOSE__URI` | Unaffected, unless the pinned URI names no database or carries an environment suffix. A CI database called `myproject-ci` is fine; one called `myproject-ci-staging` is now refused |
|
|
129
134
|
| Projects not generated from `nest-server-starter` | Nothing to do |
|
|
130
135
|
|
|
131
136
|
---
|
|
@@ -133,11 +138,11 @@ refusal list *is* the specification, and reverting the anchoring turns 13 cases
|
|
|
133
138
|
## Troubleshooting
|
|
134
139
|
|
|
135
140
|
**`Refusing to dropDatabase("…"): not a recognized disposable test database`**
|
|
136
|
-
Your `
|
|
141
|
+
Your `NSC__MONGOOSE__URI` points at something the guard will not delete. That is the guard working. Check
|
|
137
142
|
whether the URI is aimed at your development database — an `lt dev` shell exports it that way — and
|
|
138
143
|
point it at a disposable test database instead. Do not loosen the pattern to get past this.
|
|
139
144
|
|
|
140
|
-
**`Refusing to use
|
|
145
|
+
**`Refusing to use NSC__MONGOOSE__URI="…": it names no database`**
|
|
141
146
|
The URI has no path (`mongodb://host` rather than `mongodb://host/mydb`). Add the database name.
|
|
142
147
|
|
|
143
148
|
**`N stale database(s) skipped by the safety guard`**
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Migration Guide: 11.42.10 → 11.42.11
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
| Category | Details |
|
|
6
|
+
| -------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| **Framework API** | No change |
|
|
8
|
+
| **Test tooling** | e2e low-resource cap fixed for Vitest 4, e2e run governor hardened, two `check.mjs` false greens closed (§1–§3) — reaches your project only through this guide |
|
|
9
|
+
| **Tests** | A race in tests that upload to a route a role guard refuses (§4) |
|
|
10
|
+
| **Documentation** | `lt dev` exports `NSC__MONGOOSE__URI`, never `MONGODB_URI`; two older guides corrected (§5) |
|
|
11
|
+
| **Dependencies** | `nodemailer` 10.1.0 (minor, no API change); dev tooling (§6) |
|
|
12
|
+
| **Breaking Changes** | None |
|
|
13
|
+
| **Migration Effort** | None for the package. Starter-derived projects older than starter 11.42.10 should port §1 and §2 |
|
|
14
|
+
|
|
15
|
+
## Quick Migration
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm update @lenne.tech/nest-server
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Vendor-mode projects pick it up with the core update. No code or configuration change is required for the
|
|
22
|
+
framework itself.
|
|
23
|
+
|
|
24
|
+
**Why the rest of this guide exists:** `tests/`, `scripts/` and `vitest-e2e.config.ts` do not ship in the npm
|
|
25
|
+
tarball and are not part of the vendor file set. They are template files: `nest-server-starter` ships them,
|
|
26
|
+
and every project generated from it holds a private copy that no update channel touches. The sections below
|
|
27
|
+
say which starter version already carries each fix, so you can tell whether your copy needs it.
|
|
28
|
+
|
|
29
|
+
## 1. e2e low-resource mode: `maxWorkers` instead of `poolOptions` (Vitest 4)
|
|
30
|
+
|
|
31
|
+
Already in projects generated from **starter 11.42.10 or later**.
|
|
32
|
+
|
|
33
|
+
Vitest 4 removed `test.poolOptions`. The low-resource mode in `vitest-e2e.config.ts` still set
|
|
34
|
+
`poolOptions.forks.maxForks`, so the worker cap was announced on stderr and then discarded — measured: a run
|
|
35
|
+
logging `maxForks=2` used 8 workers on a 12-core machine, the same run with `maxWorkers` used 2. Low-resource
|
|
36
|
+
mode only raised the timeouts, and overlapping e2e runs (several sessions, `lt dev test` next to `check`) kept
|
|
37
|
+
starving each other into spurious 401s and timeouts.
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
// Before
|
|
41
|
+
...(LOW_RESOURCE ? { poolOptions: { forks: { maxForks: LOW_RESOURCE_FORKS, minForks: 1 } } } : {}),
|
|
42
|
+
|
|
43
|
+
// After
|
|
44
|
+
maxWorkers: LOW_RESOURCE ? LOW_RESOURCE_FORKS : undefined,
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`undefined` leaves Vitest's default in place for a normal run. `minWorkers` does not exist in Vitest 4 — drop
|
|
48
|
+
`minForks` rather than translating it. Also rename the option in the stderr announcement, so the one line that
|
|
49
|
+
reports the cap names an option that exists.
|
|
50
|
+
|
|
51
|
+
A type check does not catch this: under `module: commonjs`, Vitest's config type collapses to `any`, so a
|
|
52
|
+
removed option compiles cleanly. The starter pins it with `tests/unit/vitest-e2e-config.spec.ts`.
|
|
53
|
+
|
|
54
|
+
**Not for your project: the framework's GitHub-runner exception.** nest-server additionally skips the cap when
|
|
55
|
+
the load signal is the only trigger and `RUNNER_ENVIRONMENT === 'github-hosted'`: a GitHub-hosted runner runs
|
|
56
|
+
one job per VM, so the load it sees is the job's own unit step, and the cap measurably slowed every build
|
|
57
|
+
(133 s → 198 s mean e2e time). A shared GitLab runner sets `CI` but not `RUNNER_ENVIRONMENT`, and there the
|
|
58
|
+
load is real contention — keep the cap.
|
|
59
|
+
|
|
60
|
+
## 2. e2e run governor (`tests/e2e-run-slots.ts`) hardened
|
|
61
|
+
|
|
62
|
+
Already in projects generated from **starter 11.42.10 or later**.
|
|
63
|
+
|
|
64
|
+
The slot directory under `os.tmpdir()` is shared by every lt project on the machine. Three fixes, each pinned
|
|
65
|
+
by a test in `tests/unit/e2e-run-slots.spec.ts`:
|
|
66
|
+
|
|
67
|
+
| Defect | Fix |
|
|
68
|
+
| ------ | --- |
|
|
69
|
+
| A slot whose PID was recycled by an unrelated long-lived process counted as an active run forever | Reclaim a slot older than six hours even when its PID answers |
|
|
70
|
+
| On a multi-user Linux host (`/tmp` world-writable) a planted `<pid>.slot` symlink made the write follow it | Create the directory `0o700`, unlink the own path first, write with `flag: 'wx', mode: 0o600` |
|
|
71
|
+
| An unwritable slot directory threw out of `acquireRunSlot()` and aborted the suite, despite the documented fail-open | Catch the claim; the run proceeds ungoverned |
|
|
72
|
+
|
|
73
|
+
The easiest port is to copy `tests/e2e-run-slots.ts` and its spec from the current starter; the file has no
|
|
74
|
+
project-specific content.
|
|
75
|
+
|
|
76
|
+
## 3. `scripts/check.mjs`: two false greens
|
|
77
|
+
|
|
78
|
+
Already in projects generated from **starter 11.40.0 or later**. nest-server's own copy caught up in this
|
|
79
|
+
release.
|
|
80
|
+
|
|
81
|
+
- **The "Vulnerabilities" summary line tested `audit.counts` before `audit.degraded`.** A silent audit outage
|
|
82
|
+
(exit 0, all-zero JSON, advisory service unreachable) keeps `counts` set, so the summary printed
|
|
83
|
+
`critical 0 · high 0 · …` for a run that never reached the service. Test `degraded` first.
|
|
84
|
+
- **The CLI guard compared `resolve(process.argv[1])` with the module's own path.** Node resolves the main
|
|
85
|
+
module's symlinks for `import.meta.url` but keeps `argv[1]` as typed, so a start through a symlink — on macOS
|
|
86
|
+
any absolute path under `/tmp` — skipped the pipeline and exited 0. Compare both sides through
|
|
87
|
+
`realpathSync`, and exit 1 when the entry cannot be resolved.
|
|
88
|
+
|
|
89
|
+
## 4. Tests that upload to a refused route: send no file
|
|
90
|
+
|
|
91
|
+
Already in projects generated from **starter 11.41.9 or later** (for the avatar upload test).
|
|
92
|
+
|
|
93
|
+
When a role guard refuses a multipart upload route, it answers before the file interceptor reads the body. A
|
|
94
|
+
test that still attaches a file races that answer: the 401/403 arrives while the client is writing the
|
|
95
|
+
multipart body, and the write fails with `EPIPE` (observed 1 run in 14 in this repository with retries off).
|
|
96
|
+
The file cannot change the guard's answer, so send none — an open route then answers 400 for the missing file,
|
|
97
|
+
so the test still fails if the guard is gone:
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// Before
|
|
101
|
+
await testHelper.rest('/files/upload', { attachments: { file: local }, statusCode: 401 });
|
|
102
|
+
|
|
103
|
+
// After
|
|
104
|
+
await testHelper.rest('/files/upload', { method: 'POST', statusCode: 401 });
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Search your `tests/` for `attachments:` next to `statusCode: 401` or `403`.
|
|
108
|
+
|
|
109
|
+
## 5. Documentation corrections: `NSC__MONGOOSE__URI`, not `MONGODB_URI`
|
|
110
|
+
|
|
111
|
+
`lt dev` exports `NSC__MONGOOSE__URI` (and `DATABASE_URL`); it has never set `MONGODB_URI`. The guides
|
|
112
|
+
[11.36.3 → 11.36.4](./11.36.3-to-11.36.4.md) and [11.27.2 → 11.27.3](./11.27.2-to-11.27.3.md) named
|
|
113
|
+
`MONGODB_URI` where a starter-derived project's `tests/global-setup.ts` reads `NSC__MONGOOSE__URI`. Both are
|
|
114
|
+
corrected. The steps in them were right for your project — only the variable name was wrong, so nothing needs
|
|
115
|
+
redoing unless you adapted a script to the wrong name.
|
|
116
|
+
|
|
117
|
+
## 6. Dependency updates
|
|
118
|
+
|
|
119
|
+
- **`nodemailer` 10.0.16 → 10.1.0** — minor release: hardened message streams, SMTP connection and pool
|
|
120
|
+
handling, SMTP and encoding fixes. No API change; the framework's real-SMTP round-trip test passes. A project
|
|
121
|
+
that carries a lock-step `nodemailer` override (nest-server-starter does) should raise it:
|
|
122
|
+
|
|
123
|
+
```yaml
|
|
124
|
+
# Before
|
|
125
|
+
overrides:
|
|
126
|
+
'nodemailer@<10.0.16': '10.0.16'
|
|
127
|
+
|
|
128
|
+
# After
|
|
129
|
+
overrides:
|
|
130
|
+
'nodemailer@<10.1.0': '10.1.0'
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- **Development tooling only:** `@aws-sdk/*` 3.1149.0, `bullmq` 6.3.12, `smtp-server` 3.19.19, `vite` 8.3.4,
|
|
134
|
+
`@types/node` 26.6.5, `@types/lodash` 4.17.26. If your project pins `@types/node` exactly, raise it to 26.6.5
|
|
135
|
+
so a fresh install does not keep two copies.
|
|
136
|
+
|
|
137
|
+
Unchanged on purpose: `express` stays 5.2.1, because `@nestjs/platform-express` 11.2.7 pins it exactly — a
|
|
138
|
+
direct bump would put two copies of express into your tree. `better-auth` stays on 1.7.7, the current release.
|
|
139
|
+
|
|
140
|
+
## Compatibility Notes
|
|
141
|
+
|
|
142
|
+
| Pattern | Status |
|
|
143
|
+
| ------- | ------ |
|
|
144
|
+
| npm-mode and vendor-mode projects | Unaffected by the package update; §1–§4 apply to your own `tests/` and `scripts/` |
|
|
145
|
+
| Projects generated from starter ≥ 11.42.10 | §1–§4 already present |
|
|
146
|
+
| Projects not generated from `nest-server-starter` | Nothing to do |
|
|
147
|
+
| CI on a shared GitLab runner | Keep the low-resource cap; do not add a GitHub-runner exception |
|
|
148
|
+
|
|
149
|
+
## Troubleshooting
|
|
150
|
+
|
|
151
|
+
**`[e2e] low-resource mode: … -> maxForks=…` in your log**
|
|
152
|
+
Your copy still sets `poolOptions` — the cap is not applied. Port §1.
|
|
153
|
+
|
|
154
|
+
**`[e2e-governor] could not claim a slot (…) — proceeding without the governor.`**
|
|
155
|
+
The slot directory is not writable (owned by another user, read-only tmpdir). The run continues, ungoverned.
|
|
156
|
+
Point `LT_E2E_SLOT_DIR` at a writable directory to get the governor back.
|
|
157
|
+
|
|
158
|
+
## Module Documentation
|
|
159
|
+
|
|
160
|
+
- [`.claude/rules/testing.md`](../.claude/rules/testing.md) — run governor, low-resource mode, drop guard
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Migration Guide: 11.42.9 → 11.42.10
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
| Category | Details |
|
|
6
|
+
| -------------------- | --------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| **Requirement** | `engines.node` is now `>= 22.15` (was `>= 22.12`). In practice the floor already applied — see §1 |
|
|
8
|
+
| **Security** | Recommended `@graphql-tools/utils` override target moves from 12.0.1 to 12.0.3 (§2) |
|
|
9
|
+
| **Dependencies** | `nodemailer` 10.0.16 (bug fixes only). Dev tooling: transitive `handlebars` 4.7.10 (§3) |
|
|
10
|
+
| **Breaking Changes** | None in the API |
|
|
11
|
+
| **Migration Effort** | None for projects on Node ≥ 22.15. Projects that carry their own `@graphql-tools/utils` override should raise it (§2) |
|
|
12
|
+
|
|
13
|
+
## Quick Migration
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm update @lenne.tech/nest-server
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Vendor-mode projects pick it up with the core update. No code or configuration change is required.
|
|
20
|
+
|
|
21
|
+
## 1. Node ≥ 22.15
|
|
22
|
+
|
|
23
|
+
The declared minimum Node version rises from 22.12 to 22.15. This changes the declaration, not the reality:
|
|
24
|
+
`@apollo/server` resolves `@graphql-tools/schema` 10.1.3, which requests `@graphql-tools/utils ^12.0.3`, and
|
|
25
|
+
that in turn requires `@whatwg-node/promise-helpers` 2 — whose own `engines` field demands Node `>=22.15.0`.
|
|
26
|
+
Every fresh install of a GraphQL-enabled project has carried that requirement since those releases came out.
|
|
27
|
+
The framework's `engines` field now says so instead of promising a floor its own dependency tree does not
|
|
28
|
+
honour.
|
|
29
|
+
|
|
30
|
+
Check the Node version wherever the server runs:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
node --version # must print v22.15.0 or newer (any Node 24 qualifies)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The places to look: the Docker base image (`FROM node:…`), the CI runner's Node version, and the version a
|
|
37
|
+
host or PaaS pins. The starter's Dockerfile and the framework's own CI already run Node 24.
|
|
38
|
+
|
|
39
|
+
## 2. `@graphql-tools/utils` override: target 12.0.3
|
|
40
|
+
|
|
41
|
+
Overrides in this package's `pnpm-workspace.yaml` do not reach your project (see
|
|
42
|
+
[security-overrides.md](../docs/security-overrides.md)), so a project that copied the
|
|
43
|
+
`@graphql-tools/utils` entry for GHSA-7mx3-vvmw-hjmv holds its own. Until now the recommended target was
|
|
44
|
+
12.0.1, because 12.0.2+ needs Node ≥ 22.15. With the framework's floor at 22.15, take the newest 12.x:
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
# Before
|
|
48
|
+
overrides:
|
|
49
|
+
'@graphql-tools/utils@>=12.0.0 <12.0.1': '12.0.1'
|
|
50
|
+
|
|
51
|
+
# After
|
|
52
|
+
overrides:
|
|
53
|
+
'@graphql-tools/utils@>=12.0.0 <12.0.3': '12.0.3'
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pnpm install
|
|
58
|
+
pnpm update --depth Infinity @graphql-tools/schema @graphql-tools/merge
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Why it matters beyond tidiness: the key intersects the `^12.0.0` range that `@graphql-tools/schema` and
|
|
62
|
+
`@graphql-tools/merge` request, so a target behind the newest 12.x holds them back too. Commit
|
|
63
|
+
`pnpm-workspace.yaml` and `pnpm-lock.yaml` together — a workspace file without the re-installed lockfile fails
|
|
64
|
+
every `pnpm install --frozen-lockfile`, typically in the Docker build.
|
|
65
|
+
|
|
66
|
+
Afterwards `@nestjs/graphql` 13.4.5 still brings its own exact-pinned `@graphql-tools/schema` 10.1.0 /
|
|
67
|
+
`merge` 9.2.3 next to the 10.1.3 / 9.2.6 that `@apollo/server` uses. That is expected: both copies share the
|
|
68
|
+
single overridden `@graphql-tools/utils` 12.0.3 and the single `graphql`.
|
|
69
|
+
|
|
70
|
+
Projects still on Node < 22.15 keep the 12.0.1 target until they upgrade Node.
|
|
71
|
+
|
|
72
|
+
## 3. Dependency updates
|
|
73
|
+
|
|
74
|
+
- **`nodemailer` 10.0.15 → 10.0.16** — bug fixes in the address parser and cookie handling, no API change.
|
|
75
|
+
A project that carries a lock-step `nodemailer` override (nest-server-starter does) should raise it to
|
|
76
|
+
`'nodemailer@<10.0.16': '10.0.16'`.
|
|
77
|
+
- **`handlebars` 4.7.10 (dev tooling only)** — three advisories (GHSA-8r5x-fm3f-whwj, GHSA-p8wg-vrv2-v86f,
|
|
78
|
+
GHSA-xw65-4hp5-5hc7) reach projects through `@compodoc/compodoc`, which already allows the fixed version.
|
|
79
|
+
If `pnpm audit` reports them in your project, refresh the stale lockfile entry instead of adding an override:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pnpm update --depth Infinity handlebars
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Compatibility Notes
|
|
86
|
+
|
|
87
|
+
| Pattern | Status |
|
|
88
|
+
| ------- | ------ |
|
|
89
|
+
| Projects on Node 24 (starter Dockerfile, CI) | Unaffected |
|
|
90
|
+
| Projects on Node 22.12 – 22.14 | Already outside what `@graphql-tools/utils` 12.0.3 declares; upgrade Node |
|
|
91
|
+
| Vendor-mode projects | The core carries no `engines` field — check the Node version of your own runtime (§1) |
|
|
92
|
+
| `engine-strict=true` in `.npmrc` | Installs now fail on Node < 22.15 instead of warning |
|
|
93
|
+
|
|
94
|
+
## Troubleshooting
|
|
95
|
+
|
|
96
|
+
| Symptom | Cause | Fix |
|
|
97
|
+
| ------- | ----- | --- |
|
|
98
|
+
| `pnpm install` warns `Unsupported engine` for `@whatwg-node/promise-helpers` | Node older than 22.15 | Upgrade Node (§1) |
|
|
99
|
+
| `ERR_PNPM_UNSUPPORTED_ENGINE` for `@lenne.tech/nest-server` | `engine-strict` with Node < 22.15 | Upgrade Node (§1) |
|
|
100
|
+
| `pnpm audit` reports `@graphql-tools/utils` after updating | Your own override still targets an older version, or an old `@graphql-tools/schema` 10.0.x pulls utils 11.x | Raise the override and refresh schema / merge (§2) |
|
|
101
|
+
| `pnpm audit` reports `handlebars` via `@compodoc/compodoc` | Stale lockfile entry | `pnpm update --depth Infinity handlebars` (§3) |
|
|
102
|
+
|
|
103
|
+
## Module Documentation
|
|
104
|
+
|
|
105
|
+
- [Security overrides](../docs/security-overrides.md) — which overrides are load-bearing and how to write your own
|
|
106
|
+
- `.claude/rules/package-management.md` — override and suppression rules
|
|
107
|
+
|
|
108
|
+
## References
|
|
109
|
+
|
|
110
|
+
- [GHSA-7mx3-vvmw-hjmv](https://github.com/advisories/GHSA-7mx3-vvmw-hjmv) — `@graphql-tools/utils` prototype pollution
|
|
111
|
+
- [nest-server-starter](https://github.com/lenneTech/nest-server-starter) — reference project
|
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.11",
|
|
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",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"check:server-start": "cross-env NODE_ENV=local node scripts/check-server-start.mjs --entry=dist/main.js --port-env=NSC__PORT --ready=\"Server starte[dt] at\" --path=/",
|
|
35
35
|
"check:swc-tdz": "nest build -b swc -p tsconfig.swc-tdz.json && node scripts/check-swc-tdz.mjs",
|
|
36
36
|
"cnaf": "pnpm run check:naf",
|
|
37
|
-
"docs": "pnpm run docs:ci && open http://127.0.0.1:8080/
|
|
37
|
+
"docs": "pnpm run docs:ci && node scripts/open.mjs http://127.0.0.1:8080/ ./public/index.html && compodoc -p tsconfig.json -s",
|
|
38
38
|
"docs:bootstrap": "node extras/update-spectaql-version.mjs && node scripts/run-spectaql.mjs",
|
|
39
39
|
"docs:ci": "ts-node ./scripts/init-server.ts && pnpm run docs:bootstrap && compodoc -p tsconfig.json",
|
|
40
40
|
"format": "oxfmt --write src/ scripts/",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"start:prod": "cross-env NODE_ENV=production node dist/main.js",
|
|
60
60
|
"test": "pnpm run vitest:unit && pnpm run vitest",
|
|
61
61
|
"test:ci": "pnpm run vitest:unit && pnpm run vitest:ci",
|
|
62
|
-
"test:cleanup": "
|
|
62
|
+
"test:cleanup": "node scripts/clean-test-artifacts.mjs",
|
|
63
63
|
"test:cov": "pnpm run vitest:unit:cov && pnpm run vitest:cov",
|
|
64
64
|
"test:e2e": "pnpm run vitest",
|
|
65
65
|
"test:infra": "node scripts/test-infra.mjs up",
|
|
@@ -84,10 +84,10 @@
|
|
|
84
84
|
"url": "https://github.com/lenneTech/nest-server/issues"
|
|
85
85
|
},
|
|
86
86
|
"engines": {
|
|
87
|
-
"node": ">= 22.
|
|
87
|
+
"node": ">= 22.15",
|
|
88
88
|
"pnpm": "^11.0.0"
|
|
89
89
|
},
|
|
90
|
-
"packageManager": "pnpm@11.
|
|
90
|
+
"packageManager": "pnpm@11.28.5+sha512.484563d30b4c2ad27cb48aa94ff2b302dbcebc8ff6bf28816c2589886e146ce7f76f354f3bc1a438e6f5e9768c302aa0a6f7add8232903cd4cf81426cbc14d9e",
|
|
91
91
|
"dependencies": {
|
|
92
92
|
"@apollo/server": "5.5.1",
|
|
93
93
|
"@as-integrations/express5": "1.1.2",
|
|
@@ -129,7 +129,7 @@
|
|
|
129
129
|
"mongoose": "9.10.4",
|
|
130
130
|
"multer": "2.4.0",
|
|
131
131
|
"node-mailjet": "6.0.11",
|
|
132
|
-
"nodemailer": "10.0
|
|
132
|
+
"nodemailer": "10.1.0",
|
|
133
133
|
"passport": "0.7.0",
|
|
134
134
|
"passport-jwt": "4.0.1",
|
|
135
135
|
"reflect-metadata": "0.2.2",
|
|
@@ -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.1149.0",
|
|
186
|
+
"@aws-sdk/lib-storage": "3.1149.0",
|
|
187
|
+
"@aws-sdk/s3-request-presigner": "3.1149.0",
|
|
188
188
|
"@better-auth/core": "1.7.7",
|
|
189
189
|
"@better-auth/passkey": "1.7.7",
|
|
190
190
|
"@compodoc/compodoc": "2.0.0",
|
|
@@ -198,14 +198,13 @@
|
|
|
198
198
|
"@types/cookie-parser": "1.4.10",
|
|
199
199
|
"@types/ejs": "3.1.5",
|
|
200
200
|
"@types/express": "5.0.6",
|
|
201
|
-
"@types/lodash": "4.17.
|
|
201
|
+
"@types/lodash": "4.17.26",
|
|
202
202
|
"@types/multer": "2.3.0",
|
|
203
|
-
"@types/node": "26.6.
|
|
203
|
+
"@types/node": "26.6.5",
|
|
204
204
|
"@types/passport": "1.0.17",
|
|
205
205
|
"@vitest/coverage-v8": "4.1.11",
|
|
206
|
-
"ansi-colors": "4.1.3",
|
|
207
206
|
"better-auth": "1.7.7",
|
|
208
|
-
"bullmq": "6.3.
|
|
207
|
+
"bullmq": "6.3.12",
|
|
209
208
|
"cross-env": "10.1.0",
|
|
210
209
|
"ioredis": "6.0.0",
|
|
211
210
|
"nodemon": "3.1.14",
|
|
@@ -214,14 +213,14 @@
|
|
|
214
213
|
"oxfmt": "0.71.0",
|
|
215
214
|
"oxlint": "1.87.0",
|
|
216
215
|
"rimraf": "6.1.3",
|
|
217
|
-
"smtp-server": "3.19.
|
|
216
|
+
"smtp-server": "3.19.19",
|
|
218
217
|
"ts-node": "10.9.2",
|
|
219
218
|
"tsconfig-paths": "4.2.0",
|
|
220
219
|
"tsx": "4.23.15",
|
|
221
220
|
"tus-js-client": "4.3.1",
|
|
222
221
|
"typescript": "5.9.3",
|
|
223
222
|
"unplugin-swc": "2.0.0",
|
|
224
|
-
"vite": "8.3.
|
|
223
|
+
"vite": "8.3.4",
|
|
225
224
|
"vite-plugin-node": "8.0.0",
|
|
226
225
|
"vitest": "4.1.11"
|
|
227
226
|
},
|