@lenne.tech/nest-server 11.42.7 → 11.42.8
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/FRAMEWORK-API.md +1 -1
- package/dist/core/common/helpers/swagger.helper.js +12 -14
- package/dist/core/common/helpers/swagger.helper.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.controller.js +1 -0
- package/dist/core/modules/better-auth/core-better-auth.controller.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/migration-guides/11.42.7-to-11.42.8.md +74 -0
- package/package.json +2 -2
- package/src/core/common/helpers/swagger.helper.ts +25 -18
- package/src/core/modules/better-auth/core-better-auth.controller.ts +1 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Migration Guide: 11.42.7 → 11.42.8
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
| Category | Details |
|
|
6
|
+
| -------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| **Bugfix** | `setupSwagger()` enriches every operation an `@All()` route produces, including `SEARCH` (§1) |
|
|
8
|
+
| **Bugfix** | The Better-Auth pass-through route no longer appears as `/iam/{path}` in the Swagger document (§2) |
|
|
9
|
+
| **Dependencies** | dev: `vite` 8.3.3; override `js-yaml` 5.4.3 (§3) |
|
|
10
|
+
| **Breaking Changes** | None |
|
|
11
|
+
| **Migration Effort** | None for most projects. Regenerate a client built from `/api-docs-json` if you keep one (§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.
|
|
20
|
+
|
|
21
|
+
## 1. `SEARCH` operations of `@All()` routes are enriched
|
|
22
|
+
|
|
23
|
+
For an `@All()` route, `@nestjs/swagger` documents one operation per HTTP method — including
|
|
24
|
+
`SEARCH`, which no OpenAPI version lists as a path-item method. 11.42.7 walked a fixed list of
|
|
25
|
+
methods and skipped it, so that one operation stayed as Swagger built it: no API-token scope line,
|
|
26
|
+
no `security: []` on a public route, no tenant header, and `operationTags` did not reach it — it
|
|
27
|
+
landed in its own tag group next to the regrouped siblings.
|
|
28
|
+
|
|
29
|
+
The helper now reads the operations from the path item itself, so `SEARCH` (and any other method
|
|
30
|
+
`@nestjs/swagger` emits) is treated like every other operation — in the full document and in the
|
|
31
|
+
API-token view.
|
|
32
|
+
|
|
33
|
+
Nothing to change in your code. If you assert on the document in tests, a `search` operation of an
|
|
34
|
+
`@All()` route now carries the same `x-api-token-scopes`, description line and tags as its siblings.
|
|
35
|
+
|
|
36
|
+
## 2. `/iam/{path}` is gone from the document
|
|
37
|
+
|
|
38
|
+
`CoreBetterAuthController.handlePluginRoutes` (`@All('*path')`) forwards every other `/iam/*` request
|
|
39
|
+
to Better-Auth's own handler. It appeared in Swagger as eight `/iam/{path}` operations without
|
|
40
|
+
parameters or description. It is now `@ApiExcludeEndpoint()`; the route itself is unchanged.
|
|
41
|
+
|
|
42
|
+
- **Generated clients:** a client generated from `/api-docs-json` (hey-api, openapi-generator, …)
|
|
43
|
+
loses its `coreBetterAuthControllerHandlePluginRoutes*` functions on the next generation. They
|
|
44
|
+
could not express any real Better-Auth call, so nothing should depend on them — but regenerate and
|
|
45
|
+
let the compiler confirm it.
|
|
46
|
+
- **Own controller:** a project controller that **overrides** `handlePluginRoutes` (re-declaring
|
|
47
|
+
`@All('*path')`) must also re-declare `@ApiExcludeEndpoint()` to keep it out of the document.
|
|
48
|
+
Decorator metadata belongs to the method, so an override starts without it. A controller that
|
|
49
|
+
only inherits the method is covered automatically.
|
|
50
|
+
|
|
51
|
+
## 3. Dependency updates
|
|
52
|
+
|
|
53
|
+
Maintenance only, nothing to change in your project:
|
|
54
|
+
|
|
55
|
+
| Package | Old | New | Where |
|
|
56
|
+
| --- | --- | --- | --- |
|
|
57
|
+
| `vite` | 8.3.2 | 8.3.3 | devDependencies (test tooling) |
|
|
58
|
+
| `js-yaml` 5.x | 5.4.2 | 5.4.3 | override target in `pnpm-workspace.yaml` (parser bug fix) |
|
|
59
|
+
|
|
60
|
+
`mongoose` 9.11.0 / `mongodb` 7.7.0 are deliberately not part of this release: the framework and the
|
|
61
|
+
starter have to raise `mongodb` together, because two driver copies make Better-Auth's Mongo adapter
|
|
62
|
+
reject each other's ids.
|
|
63
|
+
|
|
64
|
+
## Compatibility Notes
|
|
65
|
+
|
|
66
|
+
- Both changes only affect the generated Swagger/OpenAPI document. Routing, guards and API-token
|
|
67
|
+
enforcement are unchanged.
|
|
68
|
+
- The document gets smaller: the framework's own test server goes from 142 to 134 operations.
|
|
69
|
+
|
|
70
|
+
## References
|
|
71
|
+
|
|
72
|
+
- Helper: `src/core/common/helpers/swagger.helper.ts` (`operationsOf()`)
|
|
73
|
+
- Controller: `src/core/modules/better-auth/core-better-auth.controller.ts` (`handlePluginRoutes`)
|
|
74
|
+
- Tests: `tests/unit/swagger-helper.spec.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.8",
|
|
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",
|
|
@@ -221,7 +221,7 @@
|
|
|
221
221
|
"tus-js-client": "4.3.1",
|
|
222
222
|
"typescript": "5.9.3",
|
|
223
223
|
"unplugin-swc": "2.0.0",
|
|
224
|
-
"vite": "8.3.
|
|
224
|
+
"vite": "8.3.3",
|
|
225
225
|
"vite-plugin-node": "8.0.0",
|
|
226
226
|
"vitest": "4.1.11"
|
|
227
227
|
},
|
|
@@ -55,9 +55,12 @@ export const SWAGGER_TENANT_HEADER_PARAMETER = 'TenantHeader';
|
|
|
55
55
|
/** Vendor extension listing the scopes an API token needs for an operation */
|
|
56
56
|
export const SWAGGER_API_TOKEN_SCOPES_EXTENSION = 'x-api-token-scopes';
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Fields of an OpenAPI path item that are not operations. Every other key is an operation: they are read
|
|
60
|
+
* from the path item rather than from a list of HTTP methods, because `@All()` makes @nestjs/swagger emit
|
|
61
|
+
* a `search` operation too, which no OpenAPI version lists — a fixed list left it unenriched.
|
|
62
|
+
*/
|
|
63
|
+
const PATH_ITEM_FIELDS = new Set(['$ref', 'description', 'parameters', 'servers', 'summary']);
|
|
61
64
|
|
|
62
65
|
/** An operation with the vendor extension this helper writes */
|
|
63
66
|
type EnrichedOperation = OperationObject & { [SWAGGER_API_TOKEN_SCOPES_EXTENSION]?: string[] };
|
|
@@ -243,10 +246,9 @@ export function buildApiTokenSwaggerDocument(
|
|
|
243
246
|
|
|
244
247
|
const paths: OpenAPIObject['paths'] = {};
|
|
245
248
|
for (const [path, item] of Object.entries(view.paths)) {
|
|
246
|
-
const kept:
|
|
247
|
-
for (const method of
|
|
248
|
-
|
|
249
|
-
if (!operation?.[SWAGGER_API_TOKEN_SCOPES_EXTENSION]?.length) {
|
|
249
|
+
const kept: Record<string, EnrichedOperation> = {};
|
|
250
|
+
for (const [method, operation] of operationsOf(item)) {
|
|
251
|
+
if (!operation[SWAGGER_API_TOKEN_SCOPES_EXTENSION]?.length) {
|
|
250
252
|
continue;
|
|
251
253
|
}
|
|
252
254
|
operation.security = [{ [SWAGGER_BEARER_SCHEME]: [] }];
|
|
@@ -440,25 +442,30 @@ function isRef(value: unknown): value is ReferenceObject {
|
|
|
440
442
|
|
|
441
443
|
function forEachOperation(
|
|
442
444
|
document: OpenAPIObject,
|
|
443
|
-
visit: (path: string, method:
|
|
445
|
+
visit: (path: string, method: string, operation: EnrichedOperation) => void,
|
|
444
446
|
): void {
|
|
445
447
|
for (const [path, item] of Object.entries(document.paths ?? {})) {
|
|
446
|
-
for (const method of
|
|
447
|
-
|
|
448
|
-
if (operation) {
|
|
449
|
-
visit(path, method, operation);
|
|
450
|
-
}
|
|
448
|
+
for (const [method, operation] of operationsOf(item)) {
|
|
449
|
+
visit(path, method, operation);
|
|
451
450
|
}
|
|
452
451
|
}
|
|
453
452
|
}
|
|
454
453
|
|
|
454
|
+
/** A path-item key that is not an operation: a field OpenAPI defines there, or a vendor extension. */
|
|
455
|
+
function isPathItemField(key: string): boolean {
|
|
456
|
+
return PATH_ITEM_FIELDS.has(key) || key.startsWith('x-');
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/** The operations of a path item, keyed by their lower-case HTTP method (`get`, ..., `search`). */
|
|
460
|
+
function operationsOf(item: PathItemObject): [string, EnrichedOperation][] {
|
|
461
|
+
return Object.entries(item).filter(
|
|
462
|
+
([key, value]) => !isPathItemField(key) && typeof value === 'object' && value !== null && !Array.isArray(value),
|
|
463
|
+
) as [string, EnrichedOperation][];
|
|
464
|
+
}
|
|
465
|
+
|
|
455
466
|
/** Fields of a path item that are not operations (summary, description, servers, shared parameters). */
|
|
456
467
|
function pathLevelFields(item: PathItemObject): PathItemObject {
|
|
457
|
-
|
|
458
|
-
for (const method of HTTP_METHODS) {
|
|
459
|
-
delete fields[method];
|
|
460
|
-
}
|
|
461
|
-
return fields;
|
|
468
|
+
return Object.fromEntries(Object.entries(item).filter(([key]) => isPathItemField(key))) as PathItemObject;
|
|
462
469
|
}
|
|
463
470
|
|
|
464
471
|
/**
|
|
@@ -753,6 +753,7 @@ export class CoreBetterAuthController {
|
|
|
753
753
|
* @see README.md "Architecture: Why Custom Controllers?"
|
|
754
754
|
*/
|
|
755
755
|
@All('*path')
|
|
756
|
+
@ApiExcludeEndpoint() // A pass-through to Better-Auth: one `/iam/{path}` per HTTP method, with nothing to document
|
|
756
757
|
@Roles(RoleEnum.S_EVERYONE)
|
|
757
758
|
async handlePluginRoutes(@Req() req: Request, @Res() res: Response): Promise<void> {
|
|
758
759
|
return this.handleBetterAuthPlugins(req, res);
|