@lenne.tech/nest-server 11.27.6 → 11.28.0
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/architecture.md +66 -0
- package/.claude/rules/better-auth.md +88 -2
- package/.claude/rules/package-management.md +23 -14
- package/.claude/rules/role-system.md +90 -0
- package/.claude/rules/versioning.md +17 -2
- package/CLAUDE.md +8 -2
- package/FRAMEWORK-API.md +27 -1
- package/dist/core/common/decorators/restricted.decorator.d.ts +4 -4
- package/dist/core/common/decorators/restricted.decorator.js +29 -26
- package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
- package/dist/core/common/exceptions/access-denied.exception.d.ts +4 -0
- package/dist/core/common/exceptions/access-denied.exception.js +12 -0
- package/dist/core/common/exceptions/access-denied.exception.js.map +1 -0
- package/dist/core/common/helpers/clone.helper.d.ts +6 -0
- package/dist/core/common/helpers/clone.helper.js +67 -0
- package/dist/core/common/helpers/clone.helper.js.map +1 -0
- package/dist/core/common/helpers/db.helper.d.ts +2 -14
- package/dist/core/common/helpers/db.helper.js +13 -106
- package/dist/core/common/helpers/db.helper.js.map +1 -1
- package/dist/core/common/helpers/id.helper.d.ts +15 -0
- package/dist/core/common/helpers/id.helper.js +104 -0
- package/dist/core/common/helpers/id.helper.js.map +1 -0
- package/dist/core/common/helpers/input.helper.d.ts +1 -6
- package/dist/core/common/helpers/input.helper.js +15 -72
- package/dist/core/common/helpers/input.helper.js.map +1 -1
- package/dist/core/common/helpers/service.helper.js +4 -3
- package/dist/core/common/helpers/service.helper.js.map +1 -1
- package/dist/core/common/inputs/combined-filter.input.d.ts +1 -12
- package/dist/core/common/inputs/combined-filter.input.js +2 -51
- package/dist/core/common/inputs/combined-filter.input.js.map +1 -1
- package/dist/core/common/inputs/filter.input.d.ts +10 -1
- package/dist/core/common/inputs/filter.input.js +40 -5
- package/dist/core/common/inputs/filter.input.js.map +1 -1
- package/dist/core/common/services/config.service.js +5 -5
- package/dist/core/common/services/config.service.js.map +1 -1
- package/dist/core/modules/ai/core-ai.constants.d.ts +22 -0
- package/dist/core/modules/ai/core-ai.constants.js +26 -0
- package/dist/core/modules/ai/core-ai.constants.js.map +1 -0
- 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/interfaces/ai-interaction-record.interface.d.ts +17 -0
- package/dist/core/modules/ai/interfaces/ai-interaction-record.interface.js +3 -0
- package/dist/core/modules/ai/interfaces/ai-interaction-record.interface.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-budget.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-budget.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-budget.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-connection-preference.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-connection-preference.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-connection-preference.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-connection.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-connection.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-connection.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-conversation.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-conversation.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-conversation.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-interaction.service.d.ts +2 -3
- package/dist/core/modules/ai/services/core-ai-interaction.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-interaction.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-mode.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-mode.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-mode.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-prompt-hint.service.d.ts +1 -3
- package/dist/core/modules/ai/services/core-ai-prompt-hint.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-prompt-hint.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-prompt.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-prompt.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-prompt.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-slot.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-slot.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-slot.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-tool-grant.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-tool-grant.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-tool-grant.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-tool-policy.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-tool-policy.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-tool-policy.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai.service.d.ts +2 -17
- package/dist/core/modules/ai/services/core-ai.service.js.map +1 -1
- package/dist/core/modules/auth/guards/roles.guard.js +2 -2
- package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth-roles.guard.js +3 -3
- package/dist/core/modules/better-auth/better-auth-roles.guard.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth.config.js +6 -0
- package/dist/core/modules/better-auth/better-auth.config.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.constants.d.ts +3 -0
- package/dist/core/modules/better-auth/core-better-auth.constants.js +7 -0
- package/dist/core/modules/better-auth/core-better-auth.constants.js.map +1 -0
- package/dist/core/modules/better-auth/core-better-auth.controller.js +1 -3
- package/dist/core/modules/better-auth/core-better-auth.controller.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.module.d.ts +1 -2
- package/dist/core/modules/better-auth/core-better-auth.module.js +23 -20
- package/dist/core/modules/better-auth/core-better-auth.module.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.registry.d.ts +4 -0
- package/dist/core/modules/better-auth/core-better-auth.registry.js +16 -0
- package/dist/core/modules/better-auth/core-better-auth.registry.js.map +1 -0
- package/dist/core/modules/better-auth/core-better-auth.service.d.ts +1 -2
- package/dist/core/modules/better-auth/core-better-auth.service.js +7 -6
- package/dist/core/modules/better-auth/core-better-auth.service.js.map +1 -1
- package/dist/core/modules/better-auth/index.d.ts +1 -0
- package/dist/core/modules/better-auth/index.js +1 -0
- package/dist/core/modules/better-auth/index.js.map +1 -1
- package/dist/core/modules/tenant/core-tenant-member.model.js +3 -3
- package/dist/core/modules/tenant/core-tenant-member.model.js.map +1 -1
- package/dist/core/modules/tenant/core-tenant.guard.js +7 -6
- package/dist/core/modules/tenant/core-tenant.guard.js.map +1 -1
- package/dist/core/modules/tus/tus.constants.d.ts +1 -0
- package/dist/core/modules/tus/tus.constants.js +5 -0
- package/dist/core/modules/tus/tus.constants.js.map +1 -0
- package/dist/core/modules/tus/tus.module.d.ts +1 -1
- package/dist/core/modules/tus/tus.module.js +8 -6
- package/dist/core/modules/tus/tus.module.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/server/modules/user/user.service.js +1 -1
- package/dist/server/modules/user/user.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/docs/REQUEST-LIFECYCLE.md +39 -0
- package/migration-guides/11.27.6-to-11.27.7.md +374 -0
- package/migration-guides/11.27.7-to-11.28.0.md +350 -0
- package/package.json +6 -104
- package/src/core/common/decorators/restricted.decorator.ts +67 -20
- package/src/core/common/exceptions/access-denied.exception.ts +49 -0
- package/src/core/common/helpers/clone.helper.ts +110 -0
- package/src/core/common/helpers/db.helper.ts +14 -161
- package/src/core/common/helpers/id.helper.ts +198 -0
- package/src/core/common/helpers/input.helper.ts +21 -88
- package/src/core/common/helpers/service.helper.ts +6 -4
- package/src/core/common/inputs/combined-filter.input.ts +10 -57
- package/src/core/common/inputs/filter.input.ts +92 -1
- package/src/core/common/services/config.service.ts +4 -1
- package/src/core/modules/ai/core-ai.constants.ts +92 -0
- package/src/core/modules/ai/index.ts +1 -0
- package/src/core/modules/ai/interfaces/ai-interaction-record.interface.ts +34 -0
- package/src/core/modules/ai/services/core-ai-budget.service.ts +8 -4
- package/src/core/modules/ai/services/core-ai-connection-preference.service.ts +8 -4
- package/src/core/modules/ai/services/core-ai-connection.service.ts +5 -6
- package/src/core/modules/ai/services/core-ai-conversation.service.ts +5 -6
- package/src/core/modules/ai/services/core-ai-interaction.service.ts +6 -7
- package/src/core/modules/ai/services/core-ai-mode.service.ts +8 -2
- package/src/core/modules/ai/services/core-ai-prompt-hint.service.ts +7 -4
- package/src/core/modules/ai/services/core-ai-prompt.service.ts +8 -2
- package/src/core/modules/ai/services/core-ai-slot.service.ts +7 -4
- package/src/core/modules/ai/services/core-ai-tool-grant.service.ts +8 -4
- package/src/core/modules/ai/services/core-ai-tool-policy.service.ts +8 -4
- package/src/core/modules/ai/services/core-ai.service.ts +8 -11
- package/src/core/modules/auth/guards/roles.guard.ts +5 -4
- package/src/core/modules/better-auth/better-auth-roles.guard.ts +15 -7
- package/src/core/modules/better-auth/better-auth.config.ts +16 -0
- package/src/core/modules/better-auth/core-better-auth.constants.ts +73 -0
- package/src/core/modules/better-auth/core-better-auth.controller.ts +5 -6
- package/src/core/modules/better-auth/core-better-auth.module.ts +34 -8
- package/src/core/modules/better-auth/core-better-auth.registry.ts +53 -0
- package/src/core/modules/better-auth/core-better-auth.service.ts +19 -12
- package/src/core/modules/better-auth/index.ts +9 -0
- package/src/core/modules/tenant/core-tenant-member.model.ts +8 -3
- package/src/core/modules/tenant/core-tenant.guard.ts +26 -11
- package/src/core/modules/tus/tus.constants.ts +25 -0
- package/src/core/modules/tus/tus.module.ts +7 -2
- package/src/index.ts +1 -0
- package/src/server/modules/user/user.service.ts +3 -2
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
CanActivate,
|
|
3
|
+
ExecutionContext,
|
|
4
|
+
ForbiddenException,
|
|
5
|
+
Injectable,
|
|
6
|
+
Logger,
|
|
7
|
+
OnModuleDestroy,
|
|
8
|
+
UnauthorizedException,
|
|
9
|
+
} from '@nestjs/common';
|
|
2
10
|
import { Reflector } from '@nestjs/core';
|
|
3
11
|
import { GqlContextType, GqlExecutionContext } from '@nestjs/graphql';
|
|
4
12
|
import { InjectModel } from '@nestjs/mongoose';
|
|
@@ -6,6 +14,7 @@ import { Model } from 'mongoose';
|
|
|
6
14
|
|
|
7
15
|
import { RoleEnum } from '../../common/enums/role.enum';
|
|
8
16
|
import { ConfigService } from '../../common/services/config.service';
|
|
17
|
+
import { ErrorCode } from '../error-code/error-codes';
|
|
9
18
|
import { CoreTenantMemberModel } from './core-tenant-member.model';
|
|
10
19
|
import { SKIP_TENANT_CHECK_KEY } from './core-tenant.decorators';
|
|
11
20
|
import { TENANT_MEMBER_MODEL_TOKEN, TenantMemberStatus } from './core-tenant.enums';
|
|
@@ -73,9 +82,14 @@ interface CachedTenantIds {
|
|
|
73
82
|
* 5. @SkipTenantCheck → role check against user.roles, no tenant context
|
|
74
83
|
* 6. BetterAuth auto-skip (betterAuth.skipTenantCheck config + no header) → skip, no tenant context
|
|
75
84
|
*
|
|
85
|
+
* Status codes (RFC 9110, aligned with RolesGuard since v11.28.0):
|
|
86
|
+
* - Missing authentication → 401 (re-authenticating IS the remedy, so the client must be told to)
|
|
87
|
+
* - Authenticated but lacking a right / membership → 403
|
|
88
|
+
* - S_NO_ONE → always 403 (authenticating can never unlock it)
|
|
89
|
+
*
|
|
76
90
|
* HEADER PRESENT:
|
|
77
91
|
* - System ADMIN (adminBypass: true) → set req.tenantId + isAdminBypass
|
|
78
|
-
* - No user →
|
|
92
|
+
* - No user → 401 (tenant access requires authentication)
|
|
79
93
|
* - Authenticated non-admin user:
|
|
80
94
|
* - Active member → checkRoleAccess against membership.role → set req.tenantId + tenantRole
|
|
81
95
|
* - Not active member → ALWAYS 403
|
|
@@ -86,7 +100,7 @@ interface CachedTenantIds {
|
|
|
86
100
|
* → resolveUserTenantIds with minLevel filter
|
|
87
101
|
* - Authenticated + no checkable roles → resolveUserTenantIds (all memberships)
|
|
88
102
|
* - No user + no checkable roles → pass (plugin safety net catches tenantId-schema access)
|
|
89
|
-
* - No user + checkable roles →
|
|
103
|
+
* - No user + checkable roles → 401 (authentication required)
|
|
90
104
|
*/
|
|
91
105
|
@Injectable()
|
|
92
106
|
export class CoreTenantGuard implements CanActivate, OnModuleDestroy {
|
|
@@ -216,8 +230,9 @@ export class CoreTenantGuard implements CanActivate, OnModuleDestroy {
|
|
|
216
230
|
|
|
217
231
|
// Defense-in-depth: S_NO_ONE is normally caught by RolesGuard/BetterAuthRolesGuard upstream,
|
|
218
232
|
// but guard it here too in case CoreTenantGuard runs standalone (e.g., custom guard chains).
|
|
233
|
+
// Always 403 — the same code the role guards return since v11.28.0.
|
|
219
234
|
if (roles.includes(RoleEnum.S_NO_ONE)) {
|
|
220
|
-
throw new ForbiddenException(
|
|
235
|
+
throw new ForbiddenException(ErrorCode.ACCESS_DENIED);
|
|
221
236
|
}
|
|
222
237
|
|
|
223
238
|
const sEveryoneGrantsAccess: boolean = systemCheckRoles.includes(RoleEnum.S_EVERYONE);
|
|
@@ -258,7 +273,7 @@ export class CoreTenantGuard implements CanActivate, OnModuleDestroy {
|
|
|
258
273
|
const sUserGrantsAccess: boolean = systemCheckRoles.includes(RoleEnum.S_USER);
|
|
259
274
|
if (sUserGrantsAccess) {
|
|
260
275
|
if (!user) {
|
|
261
|
-
throw new
|
|
276
|
+
throw new UnauthorizedException(ErrorCode.UNAUTHORIZED);
|
|
262
277
|
}
|
|
263
278
|
if (headerTenantId && !hasSkipDecorator) {
|
|
264
279
|
return this.handleSystemRoleWithTenantHeader(user, headerTenantId, request, isAdmin);
|
|
@@ -276,7 +291,7 @@ export class CoreTenantGuard implements CanActivate, OnModuleDestroy {
|
|
|
276
291
|
const sVerifiedGrantsAccess: boolean = systemCheckRoles.includes(RoleEnum.S_VERIFIED);
|
|
277
292
|
if (sVerifiedGrantsAccess) {
|
|
278
293
|
if (!user) {
|
|
279
|
-
throw new
|
|
294
|
+
throw new UnauthorizedException(ErrorCode.UNAUTHORIZED);
|
|
280
295
|
}
|
|
281
296
|
const isVerified = !!(user.verified || user.verifiedAt || user.emailVerified);
|
|
282
297
|
if (!isVerified) {
|
|
@@ -337,9 +352,9 @@ export class CoreTenantGuard implements CanActivate, OnModuleDestroy {
|
|
|
337
352
|
return true;
|
|
338
353
|
}
|
|
339
354
|
|
|
340
|
-
// No user + header →
|
|
355
|
+
// No user + header → 401 (tenant access requires authentication; re-auth is the remedy)
|
|
341
356
|
if (!user) {
|
|
342
|
-
throw new
|
|
357
|
+
throw new UnauthorizedException(ErrorCode.UNAUTHORIZED);
|
|
343
358
|
}
|
|
344
359
|
|
|
345
360
|
// Authenticated non-admin user: MUST be active member
|
|
@@ -375,9 +390,9 @@ export class CoreTenantGuard implements CanActivate, OnModuleDestroy {
|
|
|
375
390
|
|
|
376
391
|
// Checkable roles present
|
|
377
392
|
if (checkableRoles.length > 0) {
|
|
378
|
-
// No user + roles required → 403
|
|
393
|
+
// No user + roles required → 401 (re-auth is the remedy, so it must not be a 403)
|
|
379
394
|
if (!user) {
|
|
380
|
-
throw new
|
|
395
|
+
throw new UnauthorizedException(ErrorCode.UNAUTHORIZED);
|
|
381
396
|
}
|
|
382
397
|
|
|
383
398
|
// Check role access against user.roles (hierarchy: level comparison, normal: exact match)
|
|
@@ -604,7 +619,7 @@ export class CoreTenantGuard implements CanActivate, OnModuleDestroy {
|
|
|
604
619
|
if (checkableRoles.length > 0) {
|
|
605
620
|
// Defense-in-depth: reject unauthenticated access even if RolesGuard is absent
|
|
606
621
|
if (!user) {
|
|
607
|
-
throw new
|
|
622
|
+
throw new UnauthorizedException(ErrorCode.UNAUTHORIZED);
|
|
608
623
|
}
|
|
609
624
|
if (!isAdmin && !checkRoleAccess(checkableRoles, user.roles, undefined)) {
|
|
610
625
|
throw new ForbiddenException('Insufficient role');
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency-injection tokens of the TUS module.
|
|
3
|
+
*
|
|
4
|
+
* They live in a dedicated, import-free leaf file — never in `tus.module.ts` or a service — so that
|
|
5
|
+
* no file needing a token has to import the module (or vice versa) and close an import cycle.
|
|
6
|
+
*
|
|
7
|
+
* On a cycle, a token read at MODULE-EVALUATION time — inside an `@Inject()` decorator argument, in
|
|
8
|
+
* `design:paramtypes` metadata, or in a static field initializer — reads a `const` still in its
|
|
9
|
+
* temporal dead zone, and SWC-compiled builds (`nest start -b swc`) die at startup with:
|
|
10
|
+
*
|
|
11
|
+
* ReferenceError: Cannot access 'TUS_CONFIG' before initialization
|
|
12
|
+
*
|
|
13
|
+
* A file that imports nothing can never be mid-evaluation when someone imports it, in any module
|
|
14
|
+
* system, under any compiler. That is the whole point — keep it import-free.
|
|
15
|
+
*
|
|
16
|
+
* `tsc`, `pnpm test` and `oxlint` are all blind to a regression here; only `pnpm run check:swc-tdz`
|
|
17
|
+
* sees it. See .claude/rules/architecture.md → "DI Token Placement (SWC-Safe)".
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Token for injecting the resolved TUS configuration.
|
|
22
|
+
*
|
|
23
|
+
* Injected type: `Required<ITusConfig>`.
|
|
24
|
+
*/
|
|
25
|
+
export const TUS_CONFIG = 'TUS_CONFIG';
|
|
@@ -5,12 +5,17 @@ import { Connection } from 'mongoose';
|
|
|
5
5
|
import { ITusConfig } from '../../common/interfaces/server-options.interface';
|
|
6
6
|
import { CoreTusController } from './core-tus.controller';
|
|
7
7
|
import { CoreTusService } from './core-tus.service';
|
|
8
|
+
import { TUS_CONFIG } from './tus.constants';
|
|
8
9
|
import { normalizeTusConfig } from './interfaces/tus-config.interface';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
|
-
*
|
|
12
|
+
* @deprecated Import from `./tus.constants` instead. Re-exported only so existing deep imports keep
|
|
13
|
+
* working; the token is declared in an import-free leaf so module and services stay acyclic
|
|
14
|
+
* (SWC-safe — see tus.constants.ts).
|
|
15
|
+
*
|
|
16
|
+
* Do NOT import it from here inside the TUS module itself — that is what re-creates the cycle.
|
|
12
17
|
*/
|
|
13
|
-
export
|
|
18
|
+
export { TUS_CONFIG } from './tus.constants';
|
|
14
19
|
|
|
15
20
|
/**
|
|
16
21
|
* Options for TusModule.forRoot()
|
package/src/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ export * from './core/common/enums/logical-operator.enum';
|
|
|
26
26
|
export * from './core/common/enums/process-type.enum';
|
|
27
27
|
export * from './core/common/enums/role.enum';
|
|
28
28
|
export * from './core/common/enums/sort-order.emum';
|
|
29
|
+
export * from './core/common/exceptions/access-denied.exception';
|
|
29
30
|
export * from './core/common/filters/http-exception-log.filter';
|
|
30
31
|
export * from './core/common/helpers/common.helper';
|
|
31
32
|
export * from './core/common/helpers/config.helper';
|
|
@@ -98,9 +98,10 @@ export class UserService extends CoreUserService<User, UserInput, UserCreateInpu
|
|
|
98
98
|
*/
|
|
99
99
|
async setAvatar(file: Express.Multer.File, user: User): Promise<string> {
|
|
100
100
|
const dbUser = await this.mainDbModel.findOne({ id: user.id }).exec();
|
|
101
|
-
// Check user
|
|
101
|
+
// Check user: the token is valid but the account no longer exists, so the session really is
|
|
102
|
+
// invalid — 401 is right here. (A permission error would have to be 403, see accessDeniedException.)
|
|
102
103
|
if (!dbUser) {
|
|
103
|
-
throw new UnauthorizedException('User
|
|
104
|
+
throw new UnauthorizedException('User of the current session no longer exists');
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
// Check file
|