@lenne.tech/nest-server 11.25.4 → 11.25.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.
@@ -0,0 +1,273 @@
1
+ # Migration Guide: 11.25.3 → 11.25.5
2
+
3
+ ## Overview
4
+
5
+ | Category | Details |
6
+ |----------|---------|
7
+ | **Breaking Changes** | None |
8
+ | **New Features** | None |
9
+ | **Bugfixes** | (1) `MODULE_NOT_FOUND` at runtime for `@nestjs/*/dist/*` subpath imports — affected `node dist/main.js`, the migrate CLI, and any vendor-mode consumer. Tests passed because Vite/Vitest uses a different resolver. (#541) <br> (2) BetterAuth `Invalid trustedOrigin format: /` when running tests via Vitest with env-var-based `trustedOrigins` — the framework's own e2e config now filters Vite's auto-injected `process.env.BASE_URL='/'`. **Affects only consumer projects that build `betterAuth.trustedOrigins` or top-level `baseUrl` from `process.env.BASE_URL`** — see "BASE_URL Pitfall" below. |
10
+ | **Security** | (1) `postcss@<8.5.10` override (GHSA-qx2v-qp2m-jg93, XSS via unescaped `</style>` in CSS stringify output, transitive via `vite`). <br> (2) `axios@<1.16.0` override (extended from `<1.15.0`) covering multiple CVEs (SSRF via `NO_PROXY`, prototype pollution, header injection, CRLF injection in `form-data`, XSRF leakage, auth bypass, response tampering, no_proxy IP alias bypass, streamed upload/response bypass, `toFormData` DoS, null byte injection) — transitive via `@getbrevo/brevo` and `node-mailjet`. <br> (3) New `fast-uri@<3.1.2` override (GHSA-3vp4-mxqf-vmh4 host confusion + GHSA-q4mq-mw7v-xq57 path traversal) — transitive via `@compodoc/compodoc>@angular-devkit/*>ajv`. <br> (4) New `@babel/plugin-transform-modules-systemjs@>=7.12.0 <7.29.4` override (GHSA-7p7r-hpq8-6w8q prototype-pollution variable shadowing) — transitive via `@compodoc/compodoc>@babel/preset-env`. <br> All framework-internal — no consumer action needed. |
11
+ | **Maintenance** | Refreshed runtime + dev dependencies. Notable: `vite` 7.3.2 → **8.0.11** (major) and `vite-plugin-node` 7.0.0 → **8.0.0** (major) coupled lockstep upgrade — all 1751 framework tests pass. `mongoose` 9.4.1 → 9.6.2, `better-auth` 1.5.5 → 1.6.10, `@nestjs/apollo` & `@nestjs/graphql` 13.2.5 → 13.4.0, `@tus/*`, `mongodb` 7.1.1 → 7.2.0, `graphql` 16.13.2 → 16.14.0, plus dev tools (oxlint, oxfmt, swc, vitest, @types/node). |
12
+ | **Tooling** | `scripts/check-server-start.sh` now strips ANSI color escape sequences from the port-detection one-liner output, preventing `ERR_SOCKET_BAD_PORT` when running under workspace runners (lerna/nx). |
13
+ | **Migration Effort** | None required — update the package, run install + tests. Read "BASE_URL Pitfall" below if you build `betterAuth.trustedOrigins` or `baseUrl` from `process.env.BASE_URL` in your own `config.env.ts`. |
14
+
15
+ ---
16
+
17
+ ## Quick Migration
18
+
19
+ ```bash
20
+ # Update package
21
+ pnpm install @lenne.tech/nest-server@11.25.5
22
+
23
+ # Verify
24
+ pnpm run build
25
+ pnpm test
26
+ ```
27
+
28
+ No code changes required. All changes are backward compatible.
29
+
30
+ ---
31
+
32
+ ## Bug Fix: `.js` Suffix on `@nestjs/*/dist/*` Subpath Imports (#541)
33
+
34
+ ### Symptoms before the fix
35
+
36
+ When the framework code was executed with **pure Node** (i.e. `node dist/main.js`, `pnpm run migrate:up`, vendor-mode consumers running their bundled core), Node aborted with:
37
+
38
+ ```
39
+ Error: Cannot find module '.../node_modules/@nestjs/graphql/dist/schema-builder/storages/type-metadata.storage'
40
+ ELIFECYCLE Command failed with exit code 1.
41
+ ```
42
+
43
+ This affected:
44
+ - **npm-mode consumers**: any boot path that triggered the late `require()` in `interceptor.helper.ts:73` (e.g. when `ResponseModelInterceptor` resolves a return type via reflection at request time).
45
+ - **vendor-mode consumers**: every `pnpm run migrate:up` and every `node dist/main.js` from the second the project was integrated. Reproduces deterministically with `lt fullstack init --framework-mode vendor` and `lt fullstack convert-mode --to vendor` (see PR #541 reproducible steps).
46
+ - **Tests passed regardless** because Vite/Vitest uses an `enhanced-resolve`-based resolver that auto-appends `.js`. The bug was therefore invisible in the framework's own test suite.
47
+
48
+ ### Root cause
49
+
50
+ Several `@nestjs/*` packages declare an `exports` field of the form:
51
+
52
+ ```jsonc
53
+ {
54
+ "exports": {
55
+ ".": "./dist/index.js",
56
+ "./*": "./*"
57
+ }
58
+ }
59
+ ```
60
+
61
+ When `exports` is present, **Node honors the pattern literally** and does NOT auto-append `.js` for matched subpaths. The bare specifier
62
+ `@nestjs/graphql/dist/schema-builder/storages/type-metadata.storage` resolves to a literal path that does not exist on disk (only `.../type-metadata.storage.js` exists). Vite/Vitest implement the older "tryExtensions" heuristic, masking the issue in tests.
63
+
64
+ ### Fix
65
+
66
+ All `@nestjs/*/dist/*` subpath imports in the framework now end with `.js`:
67
+
68
+ | File | Before | After |
69
+ |---|---|---|
70
+ | `src/core/common/decorators/unified-field.decorator.ts` | `.../type-metadata.storage` | `.../type-metadata.storage.js` |
71
+ | `src/core/common/decorators/unified-field.decorator.ts` | `.../schema-object-metadata.interface` | `.../schema-object-metadata.interface.js` (now `import type`) |
72
+ | `src/core/common/helpers/interceptor.helper.ts` | `.../type-metadata.storage` (in `require()`) | `.../type-metadata.storage.js` |
73
+ | `src/core/common/interfaces/server-options.interface.ts` | `@nestjs/jwt/dist/interfaces` | `@nestjs/jwt/dist/interfaces/index.js` (now `import type`) |
74
+ | `src/core/common/interfaces/server-options.interface.ts` | `.../mongoose.health` | `.../mongoose.health.js` (now `import type`) |
75
+ | `src/core/common/interfaces/server-options.interface.ts` | `.../disk-health-options.type` | `.../disk-health-options.type.js` (now `import type`) |
76
+ | `src/core/modules/auth/guards/auth.guard.ts` | `@nestjs/passport/dist/options` | `@nestjs/passport/dist/options.js` |
77
+ | `src/core/modules/auth/guards/auth.guard.ts` | `@nestjs/passport/dist/utils/memoize.util` | `@nestjs/passport/dist/utils/memoize.util.js` |
78
+ | `src/core/modules/health-check/core-health-check.service.ts` | `.../mongoose.health` | `.../mongoose.health.js` (now `import type`) |
79
+ | `src/core/modules/health-check/core-health-check.service.ts` | `.../disk-health-options.type` | `.../disk-health-options.type.js` (now `import type`) |
80
+
81
+ Type-only imports were additionally promoted to `import type` for preventive hygiene once `verbatimModuleSyntax` is turned on.
82
+
83
+ ### Action required for consumers
84
+
85
+ **None for npm-mode consumers** — `pnpm install` pulls the patched code. The next `pnpm run build` of the consumer project keeps the (already correct) generated `node_modules/@lenne.tech/nest-server/dist/...` output, but now subsequent runtime calls into those files no longer crash.
86
+
87
+ **None for vendor-mode consumers either**, but the recommended sync flow is:
88
+
89
+ ```bash
90
+ # Option 1 — re-run the lt CLI vendor-update from your monorepo root
91
+ lt fullstack update
92
+
93
+ # Option 2 — manually pull the patched paths into your vendored core
94
+ # (only the 5 files listed above need updating — see PR #541 diff)
95
+ ```
96
+
97
+ Vendor-mode users who hit the original `Cannot find module ...type-metadata.storage` error will see it disappear immediately after the sync.
98
+
99
+ ---
100
+
101
+ ## Security: New & Extended Overrides
102
+
103
+ The following entries were added or extended in `pnpm.overrides`:
104
+
105
+ ```jsonc
106
+ {
107
+ "pnpm": {
108
+ "overrides": {
109
+ "axios@<1.16.0": "1.16.0", // extended in 11.25.5 (was <1.15.0)
110
+ "fast-uri@<3.1.2": "3.1.2", // new in 11.25.5
111
+ "@babel/plugin-transform-modules-systemjs@>=7.12.0 <7.29.4": "7.29.4", // new in 11.25.5
112
+ "postcss@<8.5.10": "8.5.12" // added in 11.25.4
113
+ }
114
+ }
115
+ }
116
+ ```
117
+
118
+ | Override | Advisory / CVE | Transitive chain | Status |
119
+ |---|---|---|---|
120
+ | `axios@<1.16.0` | Multiple CVEs (SSRF via `NO_PROXY`, prototype pollution, header injection, CRLF in `form-data`, XSRF leakage, auth bypass, response tampering, no_proxy IP alias bypass, streamed upload/response bypass, `toFormData` DoS, null byte injection) | `@getbrevo/brevo`, `node-mailjet` | Extended in 11.25.5 — remove when both upstreams ship `axios>=1.16.0`. |
121
+ | `fast-uri@<3.1.2` | GHSA-3vp4-mxqf-vmh4 (host confusion), GHSA-q4mq-mw7v-xq57 (path traversal) | `@compodoc/compodoc>@angular-devkit/schematics>@angular-devkit/core>ajv` | New in 11.25.5. |
122
+ | `@babel/plugin-transform-modules-systemjs@>=7.12.0 <7.29.4` | GHSA-7p7r-hpq8-6w8q (prototype-pollution variable shadowing in generated code) | `@compodoc/compodoc>@babel/preset-env` | New in 11.25.5. |
123
+ | `postcss@<8.5.10` | GHSA-qx2v-qp2m-jg93 (XSS via unescaped `</style>`) | `vite` | Added in 11.25.4. Remove when `vite` ships with `postcss>=8.5.10` natively. |
124
+
125
+ All entries follow the project rule that override **targets must be fixed versions** (no `^`, `~`, `>=`). All are framework-internal — no consumer action needed.
126
+
127
+ ---
128
+
129
+ ## Bug Fix: BASE_URL Pitfall in `config.env.ts` (added in 11.25.5)
130
+
131
+ ### Symptom
132
+
133
+ Tests fail in `beforeAll` with:
134
+
135
+ ```
136
+ BetterAuth configuration invalid: Invalid trustedOrigin format: /
137
+ BetterAuth configuration invalid: Invalid auto-detected trustedOrigin format: /; Invalid passkey origin format: /
138
+ ```
139
+
140
+ ### Root cause
141
+
142
+ Vite injects `process.env.BASE_URL = '/'` (its asset base path default — see `vite/dist/node/chunks/node.js`, `env: { BASE_URL, MODE, DEV, PROD }`). This is **also true under Vitest**, because Vitest sits on Vite. As a result, any consumer config that derives URLs via:
143
+
144
+ ```typescript
145
+ trustedOrigins: [process.env.BASE_URL || 'http://localhost:3000', ...] // BUG
146
+ baseUrl: process.env.BASE_URL // BUG
147
+ ```
148
+
149
+ ends up with `'/'` instead of the fallback under Vitest, because `'/'` is truthy. BetterAuth's URL validation then rejects `'/'` and the entire test boot path fails.
150
+
151
+ This was **never introduced by a specific Vite version** — Vite has had `BASE_URL='/'` injection for years. The bug only surfaces when consumers move from hardcoded URLs to env-var-driven URLs in their own `config.env.ts`.
152
+
153
+ ### Fix in your project's `config.env.ts`
154
+
155
+ ```typescript
156
+ // trustedOrigins (e.g. in your betterAuth config)
157
+ trustedOrigins: [
158
+ process.env.BASE_URL && process.env.BASE_URL !== '/' ? process.env.BASE_URL : 'http://localhost:3000',
159
+ process.env.APP_URL || 'http://localhost:3001',
160
+ ],
161
+
162
+ // top-level baseUrl
163
+ baseUrl: process.env.BASE_URL && process.env.BASE_URL !== '/' ? process.env.BASE_URL : undefined,
164
+ ```
165
+
166
+ Note: `APP_URL`, `MODE` (other than the four Vite built-ins), `DEV`, `PROD` are **not** auto-injected as `'/'`, so they don't need the same guard. Only `BASE_URL` is affected.
167
+
168
+ ### Alternative (cleanest)
169
+
170
+ Use a different env var name that doesn't collide with Vite's built-ins:
171
+
172
+ ```typescript
173
+ trustedOrigins: [process.env.API_URL || 'http://localhost:3000', process.env.APP_URL || 'http://localhost:3001'],
174
+ ```
175
+
176
+ Or use the framework's `NSC__` prefix for the merge mechanism (see `getEnvironmentObject()` in `core/common/helpers/config.helper.ts`):
177
+
178
+ ```bash
179
+ # in .env
180
+ NSC__BETTER_AUTH__TRUSTED_ORIGINS=http://localhost:3000,http://localhost:3001
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Maintenance: Dependency Refresh
186
+
187
+ | Package | 11.25.3 | 11.25.5 | Notes |
188
+ |---|---|---|---|
189
+ | `@apollo/server` | 5.5.0 | 5.5.1 | Patch — added 11.25.5. |
190
+ | `better-auth` | 1.5.5 | **1.6.10** | Minor bump. `@better-auth/core@1.6.9` declared `@opentelemetry/api` as `peerDependenciesMeta.optional` (previously required and was the upgrade blocker). 1.6.10 is a patch on top. All 1751 framework tests pass; manual smoke-testing of auth flows (sign-in, passkey, 2FA) is recommended in your project before deploying. |
191
+ | `@better-auth/passkey` | 1.5.5 | 1.6.10 | Lockstep with `better-auth`. |
192
+ | `@nestjs/apollo` | 13.2.5 | 13.4.0 | Patch + minor — fixes upstream. |
193
+ | `@nestjs/graphql` | 13.2.5 | 13.4.0 | Patch + minor — fixes upstream. |
194
+ | `@nestjs/swagger` | 11.3.0 | 11.4.2 | Patch-level fixes upstream. |
195
+ | `@tus/file-store` | 2.0.0 | 2.1.0 | Minor — fully backward compatible per upstream changelog. |
196
+ | `@tus/server` | 2.3.0 | 2.4.1 | Lockstep with `@tus/file-store`. |
197
+ | `graphql` | 16.13.2 | 16.14.0 | Minor — added 11.25.5. |
198
+ | `mongodb` | 7.1.1 | 7.2.0 | Minor — added 11.25.5 (now in sync with `mongoose@9.6.x`). |
199
+ | `mongoose` | 9.4.1 | 9.6.2 | Minor — bundled MongoDB driver now 7.2.x. |
200
+ | `nodemailer` | 8.0.5 | 8.0.7 | Patch. |
201
+ | `otpauth` | 9.5.0 | 9.5.1 | Patch. |
202
+ | `vite` | 7.3.2 | **8.0.11** | **Major** — added 11.25.5. Coupled lockstep upgrade with `vite-plugin-node@8.0.0`. All 1751 framework tests pass; consumers using their own `vitest`/`vite-plugin-node` setups should verify compatibility. |
203
+ | `vite-plugin-node` | 7.0.0 | **8.0.0** | **Major** — lockstep with `vite@8`. |
204
+ | `vitest` | 4.1.4 | 4.1.5 | Patch (lockstep with `@vitest/coverage-v8` and `@vitest/ui`). |
205
+ | `@swc/core` | 1.15.26 | 1.15.33 | Patch. |
206
+ | `@types/node` | 25.6.0 | 25.6.2 | Patch — added 11.25.5. |
207
+ | `oxfmt` | 0.45.0 | 0.48.0 | Minor — formatter, dev-only. |
208
+ | `oxlint` | 1.60.0 | 1.63.0 | Minor — linter, dev-only. |
209
+ | `pnpm` (packageManager) | 10.33.0 | 10.33.2 | Patch. |
210
+
211
+ **Knowingly not updated** (with rationale):
212
+
213
+ | Package | Current | Latest | Reason |
214
+ |---|---|---|---|
215
+ | `@getbrevo/brevo` | 3.0.1 | 5.0.4 | Major API redesign — separate PR. |
216
+ | `graphql-upload` | 15.0.2 | 17.0.0 | ESM-only — would force ESM migration of multiple modules. |
217
+ | `ts-morph` | 27.0.2 | 28.0.0 | `@compodoc/compodoc` peer-deps still pin `^27`. |
218
+ | `typescript` | 5.9.3 | 6.0.3 | `@nestjs/cli@11.0.21` pins `typescript@5.9.3`; major upgrade would conflict. |
219
+
220
+ ---
221
+
222
+ ## Tooling: ANSI-Safe Port Detection in `check-server-start.sh`
223
+
224
+ When `pnpm run check` runs under a workspace runner that wraps stdout with ANSI color codes (lerna, nx, turbo, certain CI environments), the inline Node one-liner that picks a free port can return output like:
225
+
226
+ ```
227
+ \x1b[33m50604\x1b[39m
228
+ ```
229
+
230
+ That string then enters `FREE_PORT` and crashes `net.Server#listen` with `ERR_SOCKET_BAD_PORT`. The script now strips ANSI escape sequences via `sed` (NOT via `tr -cd '0-9'`, which would corrupt the port digits because the escape codes contain digits themselves):
231
+
232
+ ```bash
233
+ FREE_PORT=$(node -e "..." | sed $'s/\x1b\\[[0-9;]*m//g' | tr -d '[:space:]')
234
+ ```
235
+
236
+ Defensive change — has no effect when no ANSI codes are present.
237
+
238
+ ---
239
+
240
+ ## Compatibility Notes
241
+
242
+ - **API surface**: unchanged. All exports from `src/index.ts` keep the same shape.
243
+ - **CoreModule.forRoot()**: unchanged.
244
+ - **Mongoose plugins, decorators, interceptors, guards**: unchanged.
245
+ - **Test contracts**: unchanged. `pnpm test` passes 1751 / 1751 cases on both `develop` HEAD and the new release.
246
+ - **Override targets**: all fixed versions per `.claude/rules/package-management.md`.
247
+
248
+ ---
249
+
250
+ ## Troubleshooting
251
+
252
+ **Q: After updating, `pnpm test` fails on tests that I had previously skipped because of the type-metadata.storage error.**
253
+ A: Those tests should now pass. If they don't, ensure your `pnpm-lock.yaml` is in sync (`pnpm install`) and the patched files were actually pulled.
254
+
255
+ **Q: Vendor-mode project still throws `Cannot find module ...type-metadata.storage` after I updated to 11.25.5.**
256
+ A: Run `lt fullstack update` from your monorepo root, or manually re-sync the five files listed in the bug-fix section above. The `lt` CLI's `fullstack update` will detect the version bump and pull the new vendored core.
257
+
258
+ **Q: My tests fail with `Invalid trustedOrigin format: /` or `Invalid passkey origin format: /` after switching `betterAuth.trustedOrigins` or `baseUrl` to `process.env.BASE_URL`.**
259
+ A: See "BASE_URL Pitfall" above. Vite/Vitest auto-inject `process.env.BASE_URL='/'`, so the `||` fallback never fires. Filter against `'/'` explicitly, use a different env var name (e.g. `API_URL`), or use the `NSC__` prefix mechanism.
260
+
261
+ **Q: `pnpm install` warns about unmet peer-deps for `typescript@^5.6.3 vs found 6.0.3`.**
262
+ A: Harmless — this is by design. We are deliberately staying on `typescript@5.9.x` because TS 6.0 was just released and ecosystem peer-dep readiness is still in flux. The warning will go away when downstream packages widen their peer ranges.
263
+
264
+ **Q: After running `pnpm run check` in a vendor-mode consumer, oxfmt complains about format issues in `src/core/core.module.ts` or `src/server/modules/file/file.controller.ts`.**
265
+ A: This is a separate `lt CLI`-side issue (the convert-mode does not run a final `oxfmt --write` pass). Fix locally with `pnpm run format` and report against the `lenneTech/cli` repo.
266
+
267
+ ---
268
+
269
+ ## Related Documentation
270
+
271
+ - **PR #541** — `fix(core): add .js suffix to @nestjs/*/dist/* subpath imports` (full diff and reproducible test plan)
272
+ - [Previous migration guide](./11.25.0-to-11.25.3.md)
273
+ - [`.claude/rules/package-management.md`](../.claude/rules/package-management.md) — fixed-version policy for `package.json` and overrides
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/nest-server",
3
- "version": "11.25.4",
3
+ "version": "11.25.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",
@@ -74,14 +74,14 @@
74
74
  "node": ">= 20"
75
75
  },
76
76
  "dependencies": {
77
- "@apollo/server": "5.5.0",
77
+ "@apollo/server": "5.5.1",
78
78
  "@as-integrations/express5": "1.1.2",
79
- "@better-auth/passkey": "1.6.9",
79
+ "@better-auth/passkey": "1.6.10",
80
80
  "@getbrevo/brevo": "3.0.1",
81
- "@nestjs/apollo": "13.3.0",
81
+ "@nestjs/apollo": "13.4.0",
82
82
  "@nestjs/common": "11.1.19",
83
83
  "@nestjs/core": "11.1.19",
84
- "@nestjs/graphql": "13.3.0",
84
+ "@nestjs/graphql": "13.4.0",
85
85
  "@nestjs/jwt": "11.0.2",
86
86
  "@nestjs/mongoose": "11.0.4",
87
87
  "@nestjs/passport": "11.0.5",
@@ -91,10 +91,10 @@
91
91
  "@nestjs/terminus": "11.1.1",
92
92
  "@nestjs/websockets": "11.1.19",
93
93
  "@tus/file-store": "2.1.0",
94
- "@tus/server": "2.4.0",
94
+ "@tus/server": "2.4.1",
95
95
  "@types/supertest": "7.2.0",
96
96
  "bcrypt": "6.0.0",
97
- "better-auth": "1.6.9",
97
+ "better-auth": "1.6.10",
98
98
  "class-transformer": "0.5.1",
99
99
  "class-validator": "0.15.1",
100
100
  "compression": "1.8.1",
@@ -102,15 +102,15 @@
102
102
  "dotenv": "17.4.2",
103
103
  "ejs": "5.0.2",
104
104
  "express": "5.2.1",
105
- "graphql": "16.13.2",
105
+ "graphql": "16.14.0",
106
106
  "graphql-query-complexity": "1.1.0",
107
107
  "graphql-subscriptions": "3.0.0",
108
108
  "graphql-upload": "15.0.2",
109
109
  "js-sha256": "0.11.1",
110
110
  "json-to-graphql-query": "2.3.0",
111
111
  "lodash": "4.18.1",
112
- "mongodb": "7.1.1",
113
- "mongoose": "9.5.0",
112
+ "mongodb": "7.2.0",
113
+ "mongoose": "9.6.2",
114
114
  "multer": "2.1.1",
115
115
  "node-mailjet": "6.0.11",
116
116
  "nodemailer": "8.0.7",
@@ -129,14 +129,14 @@
129
129
  "@nestjs/schematics": "11.1.0",
130
130
  "@nestjs/testing": "11.1.19",
131
131
  "@swc/cli": "0.8.1",
132
- "@swc/core": "1.15.32",
132
+ "@swc/core": "1.15.33",
133
133
  "@types/compression": "1.8.1",
134
134
  "@types/cookie-parser": "1.4.10",
135
135
  "@types/ejs": "3.1.5",
136
136
  "@types/express": "5.0.6",
137
137
  "@types/lodash": "4.17.24",
138
138
  "@types/multer": "2.1.0",
139
- "@types/node": "25.6.0",
139
+ "@types/node": "25.6.2",
140
140
  "@types/nodemailer": "8.0.0",
141
141
  "@types/passport": "1.0.17",
142
142
  "@vitest/coverage-v8": "4.1.5",
@@ -147,8 +147,8 @@
147
147
  "nodemon": "3.1.14",
148
148
  "npm-watch": "0.13.0",
149
149
  "otpauth": "9.5.1",
150
- "oxfmt": "0.47.0",
151
- "oxlint": "1.62.0",
150
+ "oxfmt": "0.48.0",
151
+ "oxlint": "1.63.0",
152
152
  "rimraf": "6.1.3",
153
153
  "ts-node": "10.9.2",
154
154
  "tsconfig-paths": "4.2.0",
@@ -156,8 +156,8 @@
156
156
  "tus-js-client": "4.3.1",
157
157
  "typescript": "5.9.3",
158
158
  "unplugin-swc": "1.5.9",
159
- "vite": "7.3.2",
160
- "vite-plugin-node": "7.0.0",
159
+ "vite": "8.0.11",
160
+ "vite-plugin-node": "8.0.0",
161
161
  "vitest": "4.1.5"
162
162
  },
163
163
  "main": "dist/index.js",
@@ -182,7 +182,9 @@
182
182
  "packageManager": "pnpm@10.33.2",
183
183
  "pnpm": {
184
184
  "//overrides": {
185
- "axios@<1.15.0": "Security: SSRF via NO_PROXY bypass (GHSA-3p68-rc4w-qgx5) and unrestricted cloud metadata exfiltration (GHSA-fvcv-3m26-pcqx) - transitive via @getbrevo/brevo and node-mailjet. Remove when @getbrevo/brevo ships axios>=1.15.0",
185
+ "axios@<1.16.0": "Security: Multiple CVEs in axios <1.15.2 (SSRF via NO_PROXY, prototype pollution, header injection, CRLF injection in form-data, XSRF leakage, auth bypass, response tampering, no_proxy IP alias bypass, streamed upload/response bypass, toFormData DoS, null byte injection) - transitive via @getbrevo/brevo and node-mailjet. Remove when @getbrevo/brevo and node-mailjet ship axios>=1.16.0",
186
+ "fast-uri@<3.1.2": "Security: host confusion (GHSA-3vp4-mxqf-vmh4) and path traversal (GHSA-q4mq-mw7v-xq57) in fast-uri <3.1.2 - transitive via @compodoc/compodoc>@angular-devkit/schematics>@angular-devkit/core>ajv",
187
+ "@babel/plugin-transform-modules-systemjs@>=7.12.0 <7.29.4": "Security: prototype pollution-based variable shadowing (GHSA-7p7r-hpq8-6w8q) generates unsafe code - transitive via @compodoc/compodoc>@babel/preset-env",
186
188
  "minimatch@<3.1.5": "Security: RegExp DoS (GHSA-p8p7-x288-28g6) - transitive via @getbrevo/brevo>rewire>eslint",
187
189
  "minimatch@>=9.0.0 <9.0.9": "Security: RegExp DoS - transitive via @nestjs/cli>@swc/cli",
188
190
  "minimatch@>=10.0.0 <10.2.5": "Security: RegExp DoS - transitive via @nestjs/apollo>ts-morph>@ts-morph/common and nodemon",
@@ -204,7 +206,9 @@
204
206
  "postcss@<8.5.10": "Security: XSS via Unescaped </style> in CSS Stringify Output (GHSA-qx2v-qp2m-jg93) - transitive via vite. Remove when vite ships with postcss>=8.5.10"
205
207
  },
206
208
  "overrides": {
207
- "axios@<1.15.0": "1.15.0",
209
+ "axios@<1.16.0": "1.16.0",
210
+ "fast-uri@<3.1.2": "3.1.2",
211
+ "@babel/plugin-transform-modules-systemjs@>=7.12.0 <7.29.4": "7.29.4",
208
212
  "minimatch@<3.1.5": "3.1.5",
209
213
  "minimatch@>=9.0.0 <9.0.9": "9.0.9",
210
214
  "minimatch@>=10.0.0 <10.2.5": "10.2.5",
package/src/config.env.ts CHANGED
@@ -32,7 +32,12 @@ const config: { [env: string]: IServerOptions } = {
32
32
  // JWT enabled by default (zero-config)
33
33
  jwt: { enabled: true, expiresIn: '15m' },
34
34
  // Passkey auto-activated when URLs can be resolved (env: 'local' → localhost defaults)
35
- passkey: { enabled: true, origin: 'http://localhost:3001', rpId: 'localhost', rpName: 'Nest Server Local' },
35
+ passkey: {
36
+ enabled: true,
37
+ origin: process.env.APP_URL || 'http://localhost:3001',
38
+ rpId: 'localhost',
39
+ rpName: 'Nest Server Local',
40
+ },
36
41
  rateLimit: { enabled: true, max: 100, windowSeconds: 60 },
37
42
  secret: process.env.BETTER_AUTH_SECRET || 'BETTER_AUTH_SECRET_LOCAL_32_CHARS_M',
38
43
  // Social providers disabled in local environment (no credentials)
@@ -42,7 +47,11 @@ const config: { [env: string]: IServerOptions } = {
42
47
  google: { clientId: '', clientSecret: '', enabled: false },
43
48
  },
44
49
  // Trusted origins for Passkey (localhost defaults)
45
- trustedOrigins: ['http://localhost:3000', 'http://localhost:3001'],
50
+ // Filter BASE_URL against '/' because Vite/Vitest auto-inject process.env.BASE_URL='/' (asset base path default).
51
+ trustedOrigins: [
52
+ process.env.BASE_URL && process.env.BASE_URL !== '/' ? process.env.BASE_URL : 'http://localhost:3000',
53
+ process.env.APP_URL || 'http://localhost:3001',
54
+ ],
46
55
  // 2FA enabled for local testing
47
56
  twoFactor: { appName: 'Nest Server Local', enabled: true },
48
57
  },
@@ -124,7 +133,7 @@ const config: { [env: string]: IServerOptions } = {
124
133
  uri: process.env.MONGODB_URI || 'mongodb://127.0.0.1/nest-server-ci',
125
134
  },
126
135
  permissions: true,
127
- port: 3000,
136
+ port: Number(process.env.PORT) || 3000,
128
137
  security: {
129
138
  checkResponseInterceptor: {
130
139
  checkObjectItself: false,
@@ -239,7 +248,7 @@ const config: { [env: string]: IServerOptions } = {
239
248
  uri: process.env.MONGODB_URI || 'mongodb://127.0.0.1/nest-server-dev',
240
249
  },
241
250
  permissions: true,
242
- port: 3000,
251
+ port: Number(process.env.PORT) || 3000,
243
252
  security: {
244
253
  checkResponseInterceptor: {
245
254
  checkObjectItself: false,
@@ -277,7 +286,12 @@ const config: { [env: string]: IServerOptions } = {
277
286
  // JWT enabled by default (zero-config)
278
287
  jwt: { enabled: true, expiresIn: '15m' },
279
288
  // Passkey auto-activated when URLs can be resolved (env: 'local' → localhost defaults)
280
- passkey: { enabled: true, origin: 'http://localhost:3001', rpId: 'localhost', rpName: 'Nest Server Local' },
289
+ passkey: {
290
+ enabled: true,
291
+ origin: process.env.APP_URL || 'http://localhost:3001',
292
+ rpId: 'localhost',
293
+ rpName: 'Nest Server Local',
294
+ },
281
295
  rateLimit: { enabled: true, max: 100, windowSeconds: 60 },
282
296
  secret: process.env.BETTER_AUTH_SECRET || 'BETTER_AUTH_SECRET_LOCAL_32_CHARS_M',
283
297
  // Social providers disabled in local environment (no credentials)
@@ -287,7 +301,11 @@ const config: { [env: string]: IServerOptions } = {
287
301
  google: { clientId: '', clientSecret: '', enabled: false },
288
302
  },
289
303
  // Trusted origins for Passkey (localhost defaults)
290
- trustedOrigins: ['http://localhost:3000', 'http://localhost:3001'],
304
+ // Filter BASE_URL against '/' because Vite/Vitest auto-inject process.env.BASE_URL='/' (asset base path default).
305
+ trustedOrigins: [
306
+ process.env.BASE_URL && process.env.BASE_URL !== '/' ? process.env.BASE_URL : 'http://localhost:3000',
307
+ process.env.APP_URL || 'http://localhost:3001',
308
+ ],
291
309
  // 2FA enabled for local testing
292
310
  twoFactor: { appName: 'Nest Server Local', enabled: true },
293
311
  },
@@ -369,7 +387,7 @@ const config: { [env: string]: IServerOptions } = {
369
387
  uri: process.env.MONGODB_URI || 'mongodb://127.0.0.1/nest-server-e2e',
370
388
  },
371
389
  permissions: true,
372
- port: 3000,
390
+ port: Number(process.env.PORT) || 3000,
373
391
  security: {
374
392
  checkResponseInterceptor: {
375
393
  checkObjectItself: false,
@@ -493,7 +511,7 @@ const config: { [env: string]: IServerOptions } = {
493
511
  permissions: {
494
512
  role: false,
495
513
  },
496
- port: 3000,
514
+ port: Number(process.env.PORT) || 3000,
497
515
  security: {
498
516
  checkResponseInterceptor: {
499
517
  checkObjectItself: false,
@@ -622,7 +640,7 @@ const config: { [env: string]: IServerOptions } = {
622
640
  // to prevent accidental connection to localhost (silent data-integrity risk).
623
641
  uri: process.env.MONGODB_URI,
624
642
  },
625
- port: 3000,
643
+ port: Number(process.env.PORT) || 3000,
626
644
  security: {
627
645
  checkResponseInterceptor: {
628
646
  checkObjectItself: false,
@@ -222,9 +222,9 @@ export class CoreModule implements NestModule {
222
222
  return connection;
223
223
  },
224
224
  },
225
- uri: 'mongodb://localhost/nest-server-default',
225
+ uri: process.env.NSC__MONGOOSE__URI || 'mongodb://localhost/nest-server-default',
226
226
  },
227
- port: 3000,
227
+ port: Number(process.env.PORT) || 3000,
228
228
  } as IServerOptions,
229
229
  options,
230
230
  );