@lenne.tech/nest-server 11.41.4 → 11.41.5
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 +3 -3
- package/CLAUDE.md +4 -2
- package/FRAMEWORK-API.md +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +1 -1
- package/dist/core/modules/migrate/migration-runner.d.ts +1 -0
- package/dist/core/modules/migrate/migration-runner.js +3 -0
- package/dist/core/modules/migrate/migration-runner.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/docs/security-overrides.md +12 -10
- package/migration-guides/11.41.4-to-11.41.5.md +144 -0
- package/package.json +16 -15
- package/src/core/common/interfaces/server-options.interface.ts +12 -6
- package/src/core/modules/migrate/README.md +15 -7
- package/src/core/modules/migrate/migration-runner.ts +9 -0
|
@@ -17,14 +17,15 @@ The framework pulls in three transitive packages that its `@nestjs/*` dependenci
|
|
|
17
17
|
| Package | Advisory | Why it cannot resolve forward on its own |
|
|
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
|
-
| `js-yaml` | [GHSA-pm4m-ph32-ghv5](https://github.com/advisories/GHSA-pm4m-ph32-ghv5) — high: exponential parsing time in flow collections (DoS)
|
|
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
21
|
| `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, the version this framework declares since 11.41.4, pins `2.4.0` |
|
|
22
22
|
|
|
23
|
-
**Status since 11.41.
|
|
24
|
-
|
|
25
|
-
`package.json` pins an older `@nestjs/graphql
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
**Status since 11.41.5:** `ws` and `multer` resolve to a patched version on their own with the
|
|
24
|
+
`@nestjs/*` versions this framework declares; their entries below are insurance for a project whose
|
|
25
|
+
own `package.json` pins an older `@nestjs/graphql` or `@nestjs/platform-express`. **`js-yaml` does
|
|
26
|
+
not**: GHSA-r3ph-w7gj-g6xm covers the `5.3.0` that `@nestjs/swagger` 11.4.7 pins, so without the
|
|
27
|
+
entry your `pnpm audit` reports it. Its key and target were raised in 11.41.5 — an entry copied
|
|
28
|
+
before that (`<5.2.2`) no longer reaches swagger's pin.
|
|
28
29
|
|
|
29
30
|
`@nestjs/graphql` is a plain `dependencies` entry, so `ws` is installed even when you run with
|
|
30
31
|
`graphQl: false`. `@nestjs/swagger` and `@nestjs/platform-express` are likewise plain `dependencies`
|
|
@@ -43,10 +44,11 @@ overrides:
|
|
|
43
44
|
# Remove once @nestjs/graphql stops pinning it.
|
|
44
45
|
'ws@>=8.0.0 <8.21.0': '8.21.3'
|
|
45
46
|
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
|
|
47
|
+
# @nestjs/swagger exact-pins js-yaml (11.4.7: 5.3.0) — GHSA-r3ph-w7gj-g6xm (moderate, patched >=5.4.1)
|
|
48
|
+
# and, for older swagger releases, GHSA-pm4m-ph32-ghv5 (high, patched >=5.2.2).
|
|
49
|
+
# Same shape as the ws entry: an exact pin cannot resolve forward. LOAD-BEARING since 11.41.5.
|
|
50
|
+
# Remove once @nestjs/swagger pins >=5.4.1 itself.
|
|
51
|
+
'js-yaml@>=5.0.0 <5.4.2': '5.4.2'
|
|
50
52
|
|
|
51
53
|
# @nestjs/platform-express <=11.2.5 exact-pins multer@2.2.0 (GHSA-wc9g-mqfw-jrwm and three more, patched >=2.3.0).
|
|
52
54
|
# Keep the target in LOCKSTEP with the multer version @lenne.tech/nest-server declares (2.4.0 since 11.41.4).
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Migration Guide: 11.41.4 → 11.41.5
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
| Category | Details |
|
|
6
|
+
| --------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| **Breaking Changes** | None in the package |
|
|
8
|
+
| **Bugfix** | `migrate down` now holds the migration lock, like `migrate up` already did |
|
|
9
|
+
| **Template change** | nest-server-starter's `docker-entrypoint.sh` now aborts the start when a migration RAN AND FAILED (§2) |
|
|
10
|
+
| **New option** | `MIGRATIONS_ALLOW_FAILURE=true` — start anyway for one deploy (starter and this repo's entrypoint) |
|
|
11
|
+
| **Dependencies** | nodemailer 9 → 10 (security; the only break is Node >= 20), js-yaml override now needed in your project (§3) |
|
|
12
|
+
| **Migration Effort** | Raise two overrides in your `pnpm-workspace.yaml` (§3); decide once whether to adopt the strict entrypoint (§2) |
|
|
13
|
+
|
|
14
|
+
## Quick Migration
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm update @lenne.tech/nest-server
|
|
18
|
+
pnpm run update # starter-based projects: aligns the framework's ecosystem (see §3)
|
|
19
|
+
pnpm run build && pnpm test
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Vendor-mode projects pick up `migration-runner.ts` through the core update.
|
|
23
|
+
|
|
24
|
+
## What's New in 11.41.5
|
|
25
|
+
|
|
26
|
+
### 1. `migrate down` holds the migration lock
|
|
27
|
+
|
|
28
|
+
Since 11.33.0, `migrate up` (`MigrationRunner.up()`) runs under the lock of the state store's lock
|
|
29
|
+
collection — `migrations_lock` by default for stores built by `createMigrationStore()` — so replicas
|
|
30
|
+
booting together serialize instead of each applying the same pending migration. `migrate down`
|
|
31
|
+
did not. A rollback is typically run while a deploy is failing, i.e. exactly while replicas restart
|
|
32
|
+
and each boots into `migrate up`; outside the lock the two read and rewrote the migration state
|
|
33
|
+
concurrently. `MigrationRunner.down()` now takes the same lock. `migrate list` only reads and stays
|
|
34
|
+
unlocked.
|
|
35
|
+
|
|
36
|
+
Nothing to do: projects using `createMigrationStore()` get it automatically. A store built with an
|
|
37
|
+
empty lock collection name (`createMigrationStore(uri, 'migrations', '')`) still runs unlocked, as
|
|
38
|
+
before.
|
|
39
|
+
|
|
40
|
+
### 2. The starter's entrypoint aborts on a migration that ran and failed
|
|
41
|
+
|
|
42
|
+
This concerns `docker-entrypoint.sh` in **nest-server-starter** (and therefore in projects created
|
|
43
|
+
from it), not the npm package. Until now the starter's entrypoint logged a failed migration and
|
|
44
|
+
started the server anyway. A failed schema migration is then indistinguishable from a good deploy
|
|
45
|
+
on every level anyone watches — health check 200, the right commit on `/meta`, drift detection
|
|
46
|
+
green, `turbo deploy --wait` converging — over an app that works against the empty collections
|
|
47
|
+
Mongoose created at boot while the data still sits under the old names.
|
|
48
|
+
|
|
49
|
+
| Situation | Before | Now |
|
|
50
|
+
| --------- | ------ | --- |
|
|
51
|
+
| A migration ran and threw | warning, server starts | **start aborted** (exit 1); the container runtime retries |
|
|
52
|
+
| `MIGRATIONS_ALLOW_FAILURE=true` | — | warning, server starts — a deliberate exception for ONE deploy |
|
|
53
|
+
| `MIGRATE_FAILURE_POLICY=warn` / `abort` | `warn` was the default | still honoured; wins over `MIGRATIONS_ALLOW_FAILURE` |
|
|
54
|
+
| Unknown value in either variable | fell back to `warn` | falls back to `abort`, with a warning |
|
|
55
|
+
| A recorded migration whose FILE is gone | warning, server starts | unchanged: warning, server starts |
|
|
56
|
+
| No migrations bundled / no CLI in the image | skipped | unchanged: skipped |
|
|
57
|
+
|
|
58
|
+
The last-but-one row is deliberate: migrations that ran everywhere may simply be deleted once a new
|
|
59
|
+
instance no longer needs them (git history restores them). The migrate CLI reports such a file as a
|
|
60
|
+
warning, and the entrypoint passes no `--strict`. A project that wants the opposite sets
|
|
61
|
+
`NSC__MIGRATE__STRICT=true` explicitly — that stays available, it is just not the default.
|
|
62
|
+
|
|
63
|
+
**What to do in an existing project:** your `docker-entrypoint.sh` is your own file, so nothing
|
|
64
|
+
changes until you adopt the new one. To adopt it, copy `docker-entrypoint.sh` from
|
|
65
|
+
nest-server-starter 11.41.5. If a deploy must go out with a migration known to fail, set
|
|
66
|
+
`MIGRATIONS_ALLOW_FAILURE=true` for that deploy and unset it again once the migration is fixed.
|
|
67
|
+
|
|
68
|
+
This repository's own `docker-entrypoint.sh` already defaulted to `abort`; it gained the
|
|
69
|
+
`MIGRATIONS_ALLOW_FAILURE` alias.
|
|
70
|
+
|
|
71
|
+
### 3. Dependency updates
|
|
72
|
+
|
|
73
|
+
| Package | 11.41.4 | 11.41.5 |
|
|
74
|
+
| ------- | ------- | ------- |
|
|
75
|
+
| `nodemailer` | 9.1.1 | **10.0.13** |
|
|
76
|
+
| `mongoose` | 9.10.2 | 9.10.3 |
|
|
77
|
+
| `@modelcontextprotocol/sdk` | 1.30.1 | 1.31.0 |
|
|
78
|
+
| dev: `@swc/core`, `@types/multer`, `@types/node`, `oxfmt`, `oxlint` | 1.16.2, 2.2.0, 26.6.2, 0.70.0, 1.85.0 | 1.16.12, 2.3.0, 26.6.3, 0.71.0, 1.86.0 |
|
|
79
|
+
|
|
80
|
+
**nodemailer 10 is a major, and it ships in a patch on purpose.** Five advisories cover 9.1.1 — two
|
|
81
|
+
of them high (GHSA-v53p-9fqp-m79j, GHSA-prgh-xp8r-p3m5), three moderate — and they are fixed only in
|
|
82
|
+
10.x; there is no 9.x backport. The single breaking change of 10.0.0 is "Node.js 20 or newer is
|
|
83
|
+
required", and this package already requires Node >= 22.12. 10.x is a TypeScript rewrite that ships
|
|
84
|
+
its own declarations; `@types/nodemailer` is no longer read. Only one thing changes for code that
|
|
85
|
+
uses nodemailer's types directly:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import type * as SMTPTransport from 'nodemailer/lib/smtp-transport';
|
|
89
|
+
|
|
90
|
+
let transport: SMTPTransport; // before: the namespace WAS the class
|
|
91
|
+
let transport: SMTPTransport.default; // nodemailer 10: the class is the default export
|
|
92
|
+
let options: SMTPTransport.Options; // unchanged
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`MailTransportOptions` in `IServerOptions` was adjusted the same way; a project that only passes a
|
|
96
|
+
plain options object (`email.smtp`) is unaffected.
|
|
97
|
+
|
|
98
|
+
**What to do:**
|
|
99
|
+
|
|
100
|
+
1. Starter-based projects: `pnpm run update` raises `mongoose` and the dev tooling to the versions above.
|
|
101
|
+
2. Two overrides `pnpm run update` does NOT touch — edit `overrides:` in your `pnpm-workspace.yaml`:
|
|
102
|
+
|
|
103
|
+
```yaml
|
|
104
|
+
# The lockstep entry from nest-server-starter. Left at 9.1.1 it forces the framework's
|
|
105
|
+
# nodemailer back DOWN to 9.1.1 — and keeps all five advisories.
|
|
106
|
+
nodemailer: 10.0.13
|
|
107
|
+
|
|
108
|
+
# @nestjs/swagger 11.4.7 (the newest 11.x) exact-pins js-yaml 5.3.0, covered by
|
|
109
|
+
# GHSA-r3ph-w7gj-g6xm (moderate, patched >=5.4.1). Replaces an older `<5.2.2` entry, which no
|
|
110
|
+
# longer reaches that pin. Background: docs/security-overrides.md.
|
|
111
|
+
'js-yaml@>=5.0.0 <5.4.2': '5.4.2'
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
3. Run `pnpm install` and `pnpm audit` — both advisories must be gone.
|
|
115
|
+
|
|
116
|
+
Overrides in this repository never reach your project (pnpm applies them only to the root of an
|
|
117
|
+
install), which is why the js-yaml entry has to be repeated there.
|
|
118
|
+
|
|
119
|
+
## Compatibility Notes
|
|
120
|
+
|
|
121
|
+
| Pattern | Status |
|
|
122
|
+
| ------- | ------ |
|
|
123
|
+
| `createMigrationStore(uri)` / `createMigrationStore(uri, 'migrations')` | Lock active for `up` and now `down` |
|
|
124
|
+
| A custom `MongoStateStore` without `lockCollectionName` | Unchanged: runs unlocked |
|
|
125
|
+
| `NSC__MIGRATE__STRICT=true` | Unchanged: a missing recorded migration file fails the run |
|
|
126
|
+
| A `nodemailer: 9.1.1` override (starter-derived projects) | Pins nodemailer 9.1.1 under the framework — raise it to `10.0.13` (§3) |
|
|
127
|
+
| Code typing `import * as X from 'nodemailer/lib/…'` as `X` | Use `X.default` (§3) |
|
|
128
|
+
| Your own `docker-entrypoint.sh` | Unchanged until you adopt the starter's (§2) |
|
|
129
|
+
|
|
130
|
+
## Troubleshooting
|
|
131
|
+
|
|
132
|
+
| Symptom | Cause | Fix |
|
|
133
|
+
| ------- | ----- | --- |
|
|
134
|
+
| Container restarts in a loop, log: `refusing to start against a possibly half-applied schema` | A migration ran and failed (new entrypoint) | Fix the migration; for one deploy, `MIGRATIONS_ALLOW_FAILURE=true` |
|
|
135
|
+
| `migrate down` waits with `Waiting for migration lock release …` | Another replica is running `migrate up` | Wait; a lock whose holder died is broken after 60 s without heartbeat |
|
|
136
|
+
| `Strict mode: N recorded migration file(s) missing` | `NSC__MIGRATE__STRICT=true` and a migration file was deleted | Restore the file from git, or unset `NSC__MIGRATE__STRICT` |
|
|
137
|
+
| `pnpm audit` still reports nodemailer advisories after the update | A `nodemailer: 9.1.1` override pins the old version | Raise it to `10.0.13` |
|
|
138
|
+
| `pnpm audit` reports GHSA-r3ph-w7gj-g6xm (js-yaml) | No (or an old `<5.2.2`) js-yaml override | Add `'js-yaml@>=5.0.0 <5.4.2': '5.4.2'` |
|
|
139
|
+
| `TS2709` / `Cannot use namespace 'SMTPTransport' as a type` | nodemailer 10 types | Use `SMTPTransport.default` |
|
|
140
|
+
|
|
141
|
+
## Module Documentation
|
|
142
|
+
|
|
143
|
+
- [Migrate module README](../src/core/modules/migrate/README.md) — locking, strict mode, CLI
|
|
144
|
+
- nest-server-starter `README.md` → Environment — `MIGRATE_FAILURE_POLICY` / `MIGRATIONS_ALLOW_FAILURE`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "11.41.
|
|
3
|
+
"version": "11.41.5",
|
|
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",
|
|
@@ -25,12 +25,13 @@
|
|
|
25
25
|
"cf": "pnpm run check:fix",
|
|
26
26
|
"check": "node scripts/check.mjs",
|
|
27
27
|
"check:consumer": "node scripts/check-consumer.mjs",
|
|
28
|
-
"check:fix": "pnpm install && pnpm run spectaql:sync && pnpm audit --fix && pnpm run check:overrides && pnpm peers check && pnpm run format && pnpm run lint:fix && pnpm run typecheck:tests && pnpm run check:swc-tdz && pnpm test && pnpm run build && pnpm run check:manifest &&
|
|
28
|
+
"check:fix": "pnpm install && pnpm run spectaql:sync && pnpm audit --fix && pnpm run check:overrides && pnpm peers check && pnpm run format && pnpm run lint:fix && pnpm run typecheck:tests && pnpm run check:swc-tdz && pnpm test && pnpm run build && pnpm run check:manifest && pnpm run check:server-start",
|
|
29
29
|
"check:manifest": "node scripts/check-package-manifest.mjs",
|
|
30
30
|
"check:mutations": "node scripts/check-mutations.mjs",
|
|
31
|
-
"check:naf": "pnpm install && pnpm run spectaql:sync && pnpm run check:overrides && pnpm peers check && pnpm run format && pnpm run lint:fix && pnpm run typecheck:tests && pnpm run check:swc-tdz && pnpm test && pnpm run build && pnpm run check:manifest &&
|
|
31
|
+
"check:naf": "pnpm install && pnpm run spectaql:sync && pnpm run check:overrides && pnpm peers check && pnpm run format && pnpm run lint:fix && pnpm run typecheck:tests && pnpm run check:swc-tdz && pnpm test && pnpm run build && pnpm run check:manifest && pnpm run check:server-start",
|
|
32
32
|
"check:overrides": "node scripts/check-overrides.mjs",
|
|
33
|
-
"check:raw": "pnpm install --frozen-lockfile && pnpm run spectaql:sync && pnpm audit && pnpm run check:overrides && pnpm peers check && pnpm run format:check && pnpm run lint && pnpm run typecheck:tests && pnpm run check:swc-tdz && pnpm test && pnpm run build && pnpm run check:manifest &&
|
|
33
|
+
"check:raw": "pnpm install --frozen-lockfile && pnpm run spectaql:sync && pnpm audit && pnpm run check:overrides && pnpm peers check && pnpm run format:check && pnpm run lint && pnpm run typecheck:tests && pnpm run check:swc-tdz && pnpm test && pnpm run build && pnpm run check:manifest && pnpm run check:server-start",
|
|
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=/",
|
|
34
35
|
"check:swc-tdz": "nest build -b swc -p tsconfig.swc-tdz.json && node scripts/check-swc-tdz.mjs",
|
|
35
36
|
"cnaf": "pnpm run check:naf",
|
|
36
37
|
"docs": "pnpm run docs:ci && open http://127.0.0.1:8080/ && open ./public/index.html && compodoc -p tsconfig.json -s ",
|
|
@@ -92,7 +93,7 @@
|
|
|
92
93
|
"@apollo/server": "5.5.1",
|
|
93
94
|
"@as-integrations/express5": "1.1.2",
|
|
94
95
|
"@getbrevo/brevo": "6.0.3",
|
|
95
|
-
"@modelcontextprotocol/sdk": "1.
|
|
96
|
+
"@modelcontextprotocol/sdk": "1.31.0",
|
|
96
97
|
"@nestjs/apollo": "13.4.5",
|
|
97
98
|
"@nestjs/common": "11.2.6",
|
|
98
99
|
"@nestjs/core": "11.2.6",
|
|
@@ -126,10 +127,10 @@
|
|
|
126
127
|
"json-to-graphql-query": "2.3.0",
|
|
127
128
|
"lodash": "4.18.1",
|
|
128
129
|
"mongodb": "7.6.0",
|
|
129
|
-
"mongoose": "9.10.
|
|
130
|
+
"mongoose": "9.10.3",
|
|
130
131
|
"multer": "2.4.0",
|
|
131
132
|
"node-mailjet": "6.0.11",
|
|
132
|
-
"nodemailer": "
|
|
133
|
+
"nodemailer": "10.0.13",
|
|
133
134
|
"passport": "0.7.0",
|
|
134
135
|
"passport-jwt": "4.0.1",
|
|
135
136
|
"reflect-metadata": "0.2.2",
|
|
@@ -177,8 +178,8 @@
|
|
|
177
178
|
}
|
|
178
179
|
},
|
|
179
180
|
"devDependencies": {
|
|
180
|
-
"@aws-sdk/client-s3": "3.
|
|
181
|
-
"@aws-sdk/s3-request-presigner": "3.
|
|
181
|
+
"@aws-sdk/client-s3": "3.1143.0",
|
|
182
|
+
"@aws-sdk/s3-request-presigner": "3.1143.0",
|
|
182
183
|
"@better-auth/core": "1.7.1",
|
|
183
184
|
"@better-auth/passkey": "1.7.1",
|
|
184
185
|
"@compodoc/compodoc": "2.0.0",
|
|
@@ -186,21 +187,21 @@
|
|
|
186
187
|
"@nestjs/schematics": "11.1.0",
|
|
187
188
|
"@nestjs/testing": "11.2.6",
|
|
188
189
|
"@swc/cli": "0.8.1",
|
|
189
|
-
"@swc/core": "1.16.
|
|
190
|
+
"@swc/core": "1.16.12",
|
|
190
191
|
"@tus/s3-store": "2.0.7",
|
|
191
192
|
"@types/compression": "1.8.1",
|
|
192
193
|
"@types/cookie-parser": "1.4.10",
|
|
193
194
|
"@types/ejs": "3.1.5",
|
|
194
195
|
"@types/express": "5.0.6",
|
|
195
196
|
"@types/lodash": "4.17.25",
|
|
196
|
-
"@types/multer": "2.
|
|
197
|
-
"@types/node": "26.6.
|
|
197
|
+
"@types/multer": "2.3.0",
|
|
198
|
+
"@types/node": "26.6.3",
|
|
198
199
|
"@types/nodemailer": "8.0.2",
|
|
199
200
|
"@types/passport": "1.0.17",
|
|
200
201
|
"@vitest/coverage-v8": "4.1.11",
|
|
201
202
|
"ansi-colors": "4.1.3",
|
|
202
203
|
"better-auth": "1.7.1",
|
|
203
|
-
"bullmq": "6.3.
|
|
204
|
+
"bullmq": "6.3.10",
|
|
204
205
|
"cross-env": "10.1.0",
|
|
205
206
|
"find-file-up": "2.0.1",
|
|
206
207
|
"husky": "9.1.7",
|
|
@@ -208,8 +209,8 @@
|
|
|
208
209
|
"nodemon": "3.1.14",
|
|
209
210
|
"npm-watch": "0.13.0",
|
|
210
211
|
"otpauth": "9.5.2",
|
|
211
|
-
"oxfmt": "0.
|
|
212
|
-
"oxlint": "1.
|
|
212
|
+
"oxfmt": "0.71.0",
|
|
213
|
+
"oxlint": "1.86.0",
|
|
213
214
|
"rimraf": "6.1.3",
|
|
214
215
|
"ts-node": "10.9.2",
|
|
215
216
|
"tsconfig-paths": "4.2.0",
|
|
@@ -37,19 +37,25 @@ export type BetterAuthFieldType = 'boolean' | 'date' | 'json' | 'number' | 'numb
|
|
|
37
37
|
* particularly useful in CI / e2e tests: `{ jsonTransport: true }` serializes
|
|
38
38
|
* outgoing mail to a JSON string and returns a valid response without any
|
|
39
39
|
* network I/O — no SMTP server, no credentials, no flakiness.
|
|
40
|
+
*
|
|
41
|
+
* The `X.default` members are the transport INSTANCE types. nodemailer >= 10 ships its own
|
|
42
|
+
* declarations, where each `nodemailer/lib/<transport>` module is `export default class` plus a
|
|
43
|
+
* module-level `Options` alias, so `import type * as X` yields a module namespace — the class is
|
|
44
|
+
* `X.default`. (`@types/nodemailer` used `export =` with a merged namespace, where `X` itself
|
|
45
|
+
* was the class.)
|
|
40
46
|
*/
|
|
41
47
|
export type MailTransportOptions =
|
|
42
|
-
| JSONTransport
|
|
48
|
+
| JSONTransport.default
|
|
43
49
|
| JSONTransport.Options
|
|
44
|
-
| SendmailTransport
|
|
50
|
+
| SendmailTransport.default
|
|
45
51
|
| SendmailTransport.Options
|
|
46
|
-
| SESTransport
|
|
52
|
+
| SESTransport.default
|
|
47
53
|
| SESTransport.Options
|
|
48
|
-
| SMTPPool
|
|
54
|
+
| SMTPPool.default
|
|
49
55
|
| SMTPPool.Options
|
|
50
|
-
| SMTPTransport
|
|
56
|
+
| SMTPTransport.default
|
|
51
57
|
| SMTPTransport.Options
|
|
52
|
-
| StreamTransport
|
|
58
|
+
| StreamTransport.default
|
|
53
59
|
| StreamTransport.Options
|
|
54
60
|
| string;
|
|
55
61
|
|
|
@@ -240,9 +240,12 @@ How the lock works, regardless of which entry point uses it:
|
|
|
240
240
|
|
|
241
241
|
This ensures that in a cluster with multiple nodes, migrations run on only one machine at a time.
|
|
242
242
|
|
|
243
|
-
**Active by default for `migrate up`.** Stores built by `createMigrationStore()` use the
|
|
244
|
-
lock collection `migrations_lock` unless another name is given, and `MigrationRunner.up()`
|
|
245
|
-
(the CLI's `up`
|
|
243
|
+
**Active by default for `migrate up` and `migrate down`.** Stores built by `createMigrationStore()` use the
|
|
244
|
+
lock collection `migrations_lock` unless another name is given, and `MigrationRunner.up()` / `.down()`
|
|
245
|
+
(the CLI's `up` / `down` commands) acquire that lock around the whole run. `down` joined later (DEV-2728): a
|
|
246
|
+
rollback is typically run while a deploy is failing, i.e. while replicas restart and each boots into
|
|
247
|
+
`migrate up` — outside the lock the two rewrote the migration state concurrently. `migrate list` only
|
|
248
|
+
reads and stays unlocked. This matters because the
|
|
246
249
|
container entrypoint runs migrations on **every** boot: without the lock, N replicas
|
|
247
250
|
starting together each read the same empty state and apply the same pending migration N
|
|
248
251
|
times. A replica that waited re-reads the state inside the lock and finds nothing pending.
|
|
@@ -530,10 +533,15 @@ Enable it via any of:
|
|
|
530
533
|
| `NSC__MIGRATE__STRICT=1\|true\|yes` env var | CLI **and** programmatic runners (resolved in the `MigrationRunner` constructor) |
|
|
531
534
|
| `new MigrationRunner({ strict: true, ... })` | programmatic |
|
|
532
535
|
|
|
533
|
-
**
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
536
|
+
**Off by default, on only when a project explicitly wants it.** Deleting migration files that
|
|
537
|
+
ran everywhere is a normal practice — a new instance never needs them, and git history restores
|
|
538
|
+
them if ever needed — and under strict mode every such deletion would refuse the boot. Turn it on
|
|
539
|
+
for images that must carry the FULL migration history. Where the history is complete by
|
|
540
|
+
design, a recorded-but-missing file can only mean a broken build (empty/miscopied
|
|
541
|
+
`migrations/` directory) or a state-store mismatch (wrong database), and refusing to boot is
|
|
542
|
+
correct. This is independent of the entrypoint's failure policy: a migration that RAN AND
|
|
543
|
+
FAILED aborts the container start by default (`MIGRATIONS_ALLOW_FAILURE=true` opts out per
|
|
544
|
+
deploy), whatever `strict` says.
|
|
537
545
|
|
|
538
546
|
### Programmatic usage (MigrationRunner)
|
|
539
547
|
|
|
@@ -297,8 +297,17 @@ export class MigrationRunner {
|
|
|
297
297
|
|
|
298
298
|
/**
|
|
299
299
|
* Rollback the last migration (down)
|
|
300
|
+
*
|
|
301
|
+
* Serialized through the same lock as `up()`. A rollback is typically run while a deploy
|
|
302
|
+
* is failing, i.e. exactly while replicas restart and each boots into `migrate up`; outside
|
|
303
|
+
* the lock the two would read and rewrite the migration state concurrently, and one of them
|
|
304
|
+
* would save a state that no longer matches the database.
|
|
300
305
|
*/
|
|
301
306
|
async down(): Promise<void> {
|
|
307
|
+
await withMigrationLock(this.options.stateStore, () => this.runDown());
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
protected async runDown(): Promise<void> {
|
|
302
311
|
const { _endMigration, _startMigration } = await import('./helpers/migration.helper');
|
|
303
312
|
|
|
304
313
|
const state = await this.options.stateStore.loadAsync();
|