@lenne.tech/nest-server 12.3.0 → 12.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/rules/configurable-features.md +2 -1
- package/.claude/rules/package-management.md +5 -1
- package/.claude/rules/testing.md +3 -3
- package/FRAMEWORK-API.md +2 -2
- package/dist/core/common/interceptors/check-security.interceptor.js +19 -2
- package/dist/core/common/interceptors/check-security.interceptor.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +1 -0
- package/dist/core/common/services/email.service.d.ts +3 -0
- package/dist/core/common/services/email.service.js +20 -0
- package/dist/core/common/services/email.service.js.map +1 -1
- package/dist/core/modules/ai/core-ai.constants.d.ts +1 -0
- package/dist/core/modules/ai/core-ai.constants.js +1 -0
- package/dist/core/modules/ai/core-ai.constants.js.map +1 -1
- package/dist/core/modules/ai/core-ai.controller.d.ts +3 -0
- package/dist/core/modules/ai/core-ai.controller.js +18 -1
- package/dist/core/modules/ai/core-ai.controller.js.map +1 -1
- package/dist/core/modules/ai/core-ai.module.js +2 -1
- package/dist/core/modules/ai/core-ai.module.js.map +1 -1
- package/dist/core/modules/ai/index.d.ts +1 -0
- package/dist/core/modules/ai/index.js +1 -0
- package/dist/core/modules/ai/index.js.map +1 -1
- package/dist/core/modules/ai/models/core-ai-status.model.d.ts +3 -0
- package/dist/core/modules/ai/models/core-ai-status.model.js +25 -0
- package/dist/core/modules/ai/models/core-ai-status.model.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth.config.js +7 -3
- package/dist/core/modules/better-auth/better-auth.config.js.map +1 -1
- package/docs/REQUEST-LIFECYCLE.md +3 -3
- package/migration-guides/12.3.0-to-12.3.1.md +136 -0
- package/migration-guides/12.3.1-to-12.3.2.md +52 -0
- package/package.json +7 -7
- package/src/core/common/interceptors/check-security.interceptor.ts +26 -2
- package/src/core/common/interfaces/server-options.interface.ts +15 -0
- package/src/core/common/services/email.service.ts +33 -1
- package/src/core/modules/ai/README.md +15 -0
- package/src/core/modules/ai/core-ai.constants.ts +4 -0
- package/src/core/modules/ai/core-ai.controller.ts +20 -1
- package/src/core/modules/ai/core-ai.module.ts +2 -0
- package/src/core/modules/ai/index.ts +1 -0
- package/src/core/modules/ai/models/core-ai-status.model.ts +16 -0
- package/src/core/modules/better-auth/INTEGRATION-CHECKLIST.md +5 -2
- package/src/core/modules/better-auth/better-auth.config.ts +9 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Body, Controller, Delete, Get, Inject, Param, Post, Put, Query, Res } from '@nestjs/common';
|
|
1
|
+
import { Body, Controller, Delete, Get, Inject, Optional, Param, Post, Put, Query, Res } from '@nestjs/common';
|
|
2
2
|
import type { Response } from 'express';
|
|
3
3
|
|
|
4
4
|
import { RESTServiceOptions } from '../../common/decorators/rest-service-options.decorator.js';
|
|
@@ -6,6 +6,7 @@ import { Roles } from '../../common/decorators/roles.decorator.js';
|
|
|
6
6
|
import { RoleEnum } from '../../common/enums/role.enum.js';
|
|
7
7
|
import type { ServiceOptions } from '../../common/interfaces/service-options.interface.js';
|
|
8
8
|
import { RequestContext } from '../../common/services/request-context.service.js';
|
|
9
|
+
import { AI_MCP_ENABLED } from './core-ai.constants.js';
|
|
9
10
|
import { CoreAiBudgetLimitCreateInput } from './inputs/core-ai-budget-limit-create.input.js';
|
|
10
11
|
import { CoreAiBudgetLimitInput } from './inputs/core-ai-budget-limit.input.js';
|
|
11
12
|
import { CoreAiConnectionCreateInput } from './inputs/core-ai-connection-create.input.js';
|
|
@@ -31,6 +32,7 @@ import { CoreAiPrompt } from './models/core-ai-prompt.model.js';
|
|
|
31
32
|
import { CoreAiSlot } from './models/core-ai-slot.model.js';
|
|
32
33
|
import { CoreAiResponse } from './models/core-ai-response.model.js';
|
|
33
34
|
import { CoreAiSettings } from './models/core-ai-settings.model.js';
|
|
35
|
+
import { CoreAiStatus } from './models/core-ai-status.model.js';
|
|
34
36
|
import { CoreAiUsageInfo } from './models/core-ai-usage-info.model.js';
|
|
35
37
|
import { CoreAiBudgetService } from './services/core-ai-budget.service.js';
|
|
36
38
|
import { CoreAiConnectionPreferenceService } from './services/core-ai-connection-preference.service.js';
|
|
@@ -48,6 +50,7 @@ import { CoreAiService } from './services/core-ai.service.js';
|
|
|
48
50
|
/**
|
|
49
51
|
* REST controller for AI prompts and connection management.
|
|
50
52
|
*
|
|
53
|
+
* - `GET /ai/status`: everyone, also without a session.
|
|
51
54
|
* - `POST /ai/prompt`: any authenticated user.
|
|
52
55
|
* - `/ai/connections*`: admin only.
|
|
53
56
|
*
|
|
@@ -77,6 +80,22 @@ export class CoreAiController {
|
|
|
77
80
|
@Inject(CoreAiUserSettingService)
|
|
78
81
|
protected readonly userSettingService: CoreAiUserSettingService;
|
|
79
82
|
|
|
83
|
+
/** Whether the MCP endpoint is registered (`ai.mcp`, 12.3.1+). A property for the same reason as the settings. */
|
|
84
|
+
@Optional()
|
|
85
|
+
@Inject(AI_MCP_ENABLED)
|
|
86
|
+
protected readonly mcpEnabled?: boolean;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* What the AI module offers on this server (12.3.1+). Public on purpose: a frontend asks before anybody signs in,
|
|
90
|
+
* to decide whether it shows the assistant at all. The route exists only while the module is registered, so a
|
|
91
|
+
* `404` is the answer "AI is off"; the body names no user data.
|
|
92
|
+
*/
|
|
93
|
+
@Get('status')
|
|
94
|
+
@Roles(RoleEnum.S_EVERYONE)
|
|
95
|
+
async status(): Promise<CoreAiStatus> {
|
|
96
|
+
return { mcp: this.mcpEnabled === true };
|
|
97
|
+
}
|
|
98
|
+
|
|
80
99
|
/**
|
|
81
100
|
* Send a prompt to the AI assistant.
|
|
82
101
|
*/
|
|
@@ -8,6 +8,7 @@ import { CoreAiMcpOAuthService } from './services/core-ai-mcp-oauth.service.js';
|
|
|
8
8
|
import { CoreAiMcpService } from './services/core-ai-mcp.service.js';
|
|
9
9
|
import { CorePersistenceModule } from '../../common/persistence/core-persistence.module.js';
|
|
10
10
|
import {
|
|
11
|
+
AI_MCP_ENABLED,
|
|
11
12
|
AI_MCP_OAUTH_CLIENT_MODEL,
|
|
12
13
|
AI_MCP_OAUTH_CODE_MODEL,
|
|
13
14
|
AI_MCP_OAUTH_REFRESH_TOKEN_MODEL,
|
|
@@ -274,6 +275,7 @@ export class CoreAiModule {
|
|
|
274
275
|
AskUserQuestionAiTool,
|
|
275
276
|
SearchToolsAiTool,
|
|
276
277
|
LlmProviderFactory,
|
|
278
|
+
{ provide: AI_MCP_ENABLED, useValue: options.mcpEnabled === true },
|
|
277
279
|
{ provide: AI_BUDGET_LIMIT_CLASS, useValue: CoreAiBudgetLimit },
|
|
278
280
|
{ provide: AI_CONNECTION_CLASS, useValue: CoreAiConnection },
|
|
279
281
|
{ provide: AI_CONNECTION_PREFERENCE_CLASS, useValue: CoreAiConnectionPreference },
|
|
@@ -57,6 +57,7 @@ export * from './models/core-ai-tool-grant.model.js';
|
|
|
57
57
|
export * from './models/core-ai-mode.model.js';
|
|
58
58
|
export * from './models/core-ai-tool-policy.model.js';
|
|
59
59
|
export * from './models/core-ai-settings.model.js';
|
|
60
|
+
export * from './models/core-ai-status.model.js';
|
|
60
61
|
export * from './models/core-ai-user-setting.model.js';
|
|
61
62
|
export * from './models/core-ai-response.model.js';
|
|
62
63
|
export * from './models/core-ai-usage-info.model.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Field, ObjectType } from '@nestjs/graphql';
|
|
2
|
+
|
|
3
|
+
import { Restricted } from '../../../common/decorators/restricted.decorator.js';
|
|
4
|
+
import { RoleEnum } from '../../../common/enums/role.enum.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* What the AI module offers on this server (12.3.1+). Answer of the public `GET /ai/status`, which exists only while
|
|
8
|
+
* the module is registered — a `404` there is the answer "AI is off". Names no user data.
|
|
9
|
+
*/
|
|
10
|
+
@ObjectType({ description: 'What the AI module offers on this server' })
|
|
11
|
+
@Restricted(RoleEnum.S_EVERYONE)
|
|
12
|
+
export class CoreAiStatus {
|
|
13
|
+
/** Whether the MCP server answers at `/ai/mcp` (`ai.mcp`). */
|
|
14
|
+
@Field(() => Boolean, { description: 'Whether the MCP server answers at /ai/mcp' })
|
|
15
|
+
mcp: boolean;
|
|
16
|
+
}
|
|
@@ -18,14 +18,17 @@ From `@lenne.tech/nest-server` 11.37.0, better-auth is **not** a dependency of t
|
|
|
18
18
|
non-optional **peer dependency**, so your project declares and owns the version:
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
pnpm add better-auth@1.7.
|
|
21
|
+
pnpm add better-auth@1.7.16 @better-auth/passkey@1.7.16 @better-auth/core@1.7.16
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
1.7.16 is the floor since nest-server 12.3.1: it closes the better-auth advisories published on 2026-11-03 (social
|
|
25
|
+
sign-in, passkeys, e-mail change links, revoked sessions with a session cache).
|
|
26
|
+
|
|
24
27
|
**Pin all three to the same exact version** — no `^`, no `~`. They are one release train, and a
|
|
25
28
|
mixed set fails in ways the type checker does not catch.
|
|
26
29
|
|
|
27
30
|
> **Do not rely on `pnpm install` to remind you.** On pnpm's default `autoInstallPeers: true` the
|
|
28
|
-
> packages are installed silently at whatever version satisfies `>=1.7.
|
|
31
|
+
> packages are installed silently at whatever version satisfies `>=1.7.16 <1.8.0` — your build stays
|
|
29
32
|
> green while the version is unpinned and free to drift. Verify with `pnpm why better-auth`.
|
|
30
33
|
|
|
31
34
|
**Why peers rather than dependencies:** in a fullstack project the frontend talks to better-auth
|
|
@@ -1065,15 +1065,20 @@ function buildPlugins(
|
|
|
1065
1065
|
rpName: normalizedPasskey.rpName,
|
|
1066
1066
|
};
|
|
1067
1067
|
|
|
1068
|
-
//
|
|
1068
|
+
// The plugin reads these three from `authenticatorSelection` only. Until 12.3.1 they were set at the top level and
|
|
1069
|
+
// ignored, so `userVerification: 'required'` enforced nothing; the plugin's own defaults fill what is not set
|
|
1070
|
+
const authenticatorSelection: Record<string, string> = {};
|
|
1069
1071
|
if (normalizedPasskey.authenticatorAttachment) {
|
|
1070
|
-
|
|
1072
|
+
authenticatorSelection.authenticatorAttachment = normalizedPasskey.authenticatorAttachment;
|
|
1071
1073
|
}
|
|
1072
1074
|
if (normalizedPasskey.residentKey) {
|
|
1073
|
-
|
|
1075
|
+
authenticatorSelection.residentKey = normalizedPasskey.residentKey;
|
|
1074
1076
|
}
|
|
1075
1077
|
if (normalizedPasskey.userVerification) {
|
|
1076
|
-
|
|
1078
|
+
authenticatorSelection.userVerification = normalizedPasskey.userVerification;
|
|
1079
|
+
}
|
|
1080
|
+
if (Object.keys(authenticatorSelection).length > 0) {
|
|
1081
|
+
passkeyOptions.authenticatorSelection = authenticatorSelection;
|
|
1077
1082
|
}
|
|
1078
1083
|
if (normalizedPasskey.webAuthnChallengeCookie) {
|
|
1079
1084
|
// The plugin reads the name from `advanced`; a top-level option is ignored
|