@lenne.tech/nest-server 12.2.0 → 12.3.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.
Files changed (152) hide show
  1. package/.claude/rules/better-auth.md +31 -4
  2. package/.claude/rules/configurable-features.md +7 -6
  3. package/.claude/rules/package-management.md +13 -1
  4. package/.claude/rules/persistence.md +2 -2
  5. package/.claude/rules/testing.md +5 -5
  6. package/.claude/rules/versioning.md +13 -2
  7. package/CLAUDE.md +5 -0
  8. package/FRAMEWORK-API.md +4 -3
  9. package/README.md +2 -2
  10. package/dist/config.env.js +2 -2
  11. package/dist/config.env.js.map +1 -1
  12. package/dist/core/common/helpers/graphql-ws-connection.helper.d.ts +4 -0
  13. package/dist/core/common/helpers/graphql-ws-connection.helper.js +17 -3
  14. package/dist/core/common/helpers/graphql-ws-connection.helper.js.map +1 -1
  15. package/dist/core/common/interfaces/server-options.interface.d.ts +8 -0
  16. package/dist/core/modules/ai/core-ai-mcp.controller.d.ts +3 -0
  17. package/dist/core/modules/ai/core-ai-mcp.controller.js +29 -0
  18. package/dist/core/modules/ai/core-ai-mcp.controller.js.map +1 -1
  19. package/dist/core/modules/ai/core-ai.constants.d.ts +2 -0
  20. package/dist/core/modules/ai/core-ai.constants.js +2 -0
  21. package/dist/core/modules/ai/core-ai.constants.js.map +1 -1
  22. package/dist/core/modules/ai/core-ai.controller.d.ts +6 -0
  23. package/dist/core/modules/ai/core-ai.controller.js +31 -1
  24. package/dist/core/modules/ai/core-ai.controller.js.map +1 -1
  25. package/dist/core/modules/ai/core-ai.module.d.ts +2 -0
  26. package/dist/core/modules/ai/core-ai.module.js +8 -1
  27. package/dist/core/modules/ai/core-ai.module.js.map +1 -1
  28. package/dist/core/modules/ai/core-ai.resolver.d.ts +6 -0
  29. package/dist/core/modules/ai/core-ai.resolver.js +32 -0
  30. package/dist/core/modules/ai/core-ai.resolver.js.map +1 -1
  31. package/dist/core/modules/ai/helpers/ai-mcp-oauth-consent.helper.d.ts +65 -1
  32. package/dist/core/modules/ai/helpers/ai-mcp-oauth-consent.helper.js +6 -3
  33. package/dist/core/modules/ai/helpers/ai-mcp-oauth-consent.helper.js.map +1 -1
  34. package/dist/core/modules/ai/helpers/ai-mcp-oauth.helper.js +48 -1
  35. package/dist/core/modules/ai/helpers/ai-mcp-oauth.helper.js.map +1 -1
  36. package/dist/core/modules/ai/helpers/ai-tool-authorization.helper.d.ts +9 -0
  37. package/dist/core/modules/ai/helpers/ai-tool-authorization.helper.js +54 -0
  38. package/dist/core/modules/ai/helpers/ai-tool-authorization.helper.js.map +1 -0
  39. package/dist/core/modules/ai/index.d.ts +7 -0
  40. package/dist/core/modules/ai/index.js +6 -0
  41. package/dist/core/modules/ai/index.js.map +1 -1
  42. package/dist/core/modules/ai/inputs/core-ai-settings.input.d.ts +3 -0
  43. package/dist/core/modules/ai/inputs/core-ai-settings.input.js +31 -0
  44. package/dist/core/modules/ai/inputs/core-ai-settings.input.js.map +1 -0
  45. package/dist/core/modules/ai/interfaces/ai-tool.interface.d.ts +2 -0
  46. package/dist/core/modules/ai/models/core-ai-settings.model.d.ts +4 -0
  47. package/dist/core/modules/ai/models/core-ai-settings.model.js +30 -0
  48. package/dist/core/modules/ai/models/core-ai-settings.model.js.map +1 -0
  49. package/dist/core/modules/ai/models/core-ai-user-setting.model.d.ts +8 -0
  50. package/dist/core/modules/ai/models/core-ai-user-setting.model.js +45 -0
  51. package/dist/core/modules/ai/models/core-ai-user-setting.model.js.map +1 -0
  52. package/dist/core/modules/ai/services/core-ai-conversation.service.d.ts +4 -1
  53. package/dist/core/modules/ai/services/core-ai-conversation.service.js +16 -4
  54. package/dist/core/modules/ai/services/core-ai-conversation.service.js.map +1 -1
  55. package/dist/core/modules/ai/services/core-ai-mcp-oauth.service.js +6 -6
  56. package/dist/core/modules/ai/services/core-ai-mcp-oauth.service.js.map +1 -1
  57. package/dist/core/modules/ai/services/core-ai-mcp.service.d.ts +27 -2
  58. package/dist/core/modules/ai/services/core-ai-mcp.service.js +118 -11
  59. package/dist/core/modules/ai/services/core-ai-mcp.service.js.map +1 -1
  60. package/dist/core/modules/ai/services/core-ai-prompt-builder.service.js +9 -6
  61. package/dist/core/modules/ai/services/core-ai-prompt-builder.service.js.map +1 -1
  62. package/dist/core/modules/ai/services/core-ai-user-setting.service.d.ts +17 -0
  63. package/dist/core/modules/ai/services/core-ai-user-setting.service.js +72 -0
  64. package/dist/core/modules/ai/services/core-ai-user-setting.service.js.map +1 -0
  65. package/dist/core/modules/ai/services/core-ai.service.d.ts +8 -3
  66. package/dist/core/modules/ai/services/core-ai.service.js +68 -29
  67. package/dist/core/modules/ai/services/core-ai.service.js.map +1 -1
  68. package/dist/core/modules/better-auth/better-auth.config.js +3 -1
  69. package/dist/core/modules/better-auth/better-auth.config.js.map +1 -1
  70. package/dist/core/modules/better-auth/core-better-auth-email-verification.service.js +2 -2
  71. package/dist/core/modules/better-auth/core-better-auth-email-verification.service.js.map +1 -1
  72. package/dist/core/modules/better-auth/core-better-auth-path-guard.middleware.d.ts +8 -0
  73. package/dist/core/modules/better-auth/core-better-auth-path-guard.middleware.js +64 -0
  74. package/dist/core/modules/better-auth/core-better-auth-path-guard.middleware.js.map +1 -0
  75. package/dist/core/modules/better-auth/core-better-auth-rate-limit.middleware.js +2 -1
  76. package/dist/core/modules/better-auth/core-better-auth-rate-limit.middleware.js.map +1 -1
  77. package/dist/core/modules/better-auth/core-better-auth-rate-limiter.service.d.ts +1 -1
  78. package/dist/core/modules/better-auth/core-better-auth-rate-limiter.service.js +5 -3
  79. package/dist/core/modules/better-auth/core-better-auth-rate-limiter.service.js.map +1 -1
  80. package/dist/core/modules/better-auth/core-better-auth.module.js +2 -0
  81. package/dist/core/modules/better-auth/core-better-auth.module.js.map +1 -1
  82. package/dist/core/modules/better-auth/index.d.ts +1 -0
  83. package/dist/core/modules/better-auth/index.js +1 -0
  84. package/dist/core/modules/better-auth/index.js.map +1 -1
  85. package/dist/core/modules/error-code/error-codes.d.ts +18 -0
  86. package/dist/core/modules/error-code/error-codes.js +16 -0
  87. package/dist/core/modules/error-code/error-codes.js.map +1 -1
  88. package/dist/core/modules/sync/core-sync.service.d.ts +1 -0
  89. package/dist/core/modules/sync/core-sync.service.js +31 -2
  90. package/dist/core/modules/sync/core-sync.service.js.map +1 -1
  91. package/dist/core/modules/tenant/core-tenant.guard.js +10 -0
  92. package/dist/core/modules/tenant/core-tenant.guard.js.map +1 -1
  93. package/dist/core/modules/tenant/core-tenant.service.d.ts +21 -1
  94. package/dist/core/modules/tenant/core-tenant.service.js +153 -1
  95. package/dist/core/modules/tenant/core-tenant.service.js.map +1 -1
  96. package/dist/server/modules/error-code/error-codes.d.ts +2 -0
  97. package/dist/test/test.helper.d.ts +1 -0
  98. package/dist/test/test.helper.js +9 -2
  99. package/dist/test/test.helper.js.map +1 -1
  100. package/docs/REQUEST-LIFECYCLE.md +3 -2
  101. package/docs/error-codes.md +14 -0
  102. package/docs/offline-sync-protocol.md +17 -8
  103. package/migration-guides/12.0.x-to-12.1.x.md +0 -1
  104. package/migration-guides/12.2.x-to-12.3.x.md +440 -0
  105. package/package.json +20 -20
  106. package/src/config.env.ts +6 -2
  107. package/src/core/common/helpers/graphql-ws-connection.helper.ts +32 -4
  108. package/src/core/common/interfaces/server-options.interface.ts +80 -8
  109. package/src/core/common/persistence/sync-model.ts +1 -1
  110. package/src/core/modules/ai/INTEGRATION-CHECKLIST.md +36 -15
  111. package/src/core/modules/ai/README.md +163 -25
  112. package/src/core/modules/ai/core-ai-mcp.controller.ts +48 -1
  113. package/src/core/modules/ai/core-ai.constants.ts +6 -0
  114. package/src/core/modules/ai/core-ai.controller.ts +36 -1
  115. package/src/core/modules/ai/core-ai.module.ts +12 -0
  116. package/src/core/modules/ai/core-ai.resolver.ts +36 -0
  117. package/src/core/modules/ai/helpers/ai-mcp-oauth-consent.helper.ts +35 -4
  118. package/src/core/modules/ai/helpers/ai-mcp-oauth.helper.ts +68 -1
  119. package/src/core/modules/ai/helpers/ai-tool-authorization.helper.ts +99 -0
  120. package/src/core/modules/ai/index.ts +18 -0
  121. package/src/core/modules/ai/inputs/core-ai-settings.input.ts +24 -0
  122. package/src/core/modules/ai/interfaces/ai-hook.interface.ts +1 -1
  123. package/src/core/modules/ai/interfaces/ai-tool.interface.ts +38 -26
  124. package/src/core/modules/ai/models/core-ai-mode.model.ts +1 -1
  125. package/src/core/modules/ai/models/core-ai-settings.model.ts +23 -0
  126. package/src/core/modules/ai/models/core-ai-tool-policy.model.ts +1 -1
  127. package/src/core/modules/ai/models/core-ai-user-setting.model.ts +46 -0
  128. package/src/core/modules/ai/services/core-ai-conversation.service.ts +31 -6
  129. package/src/core/modules/ai/services/core-ai-mcp-oauth.service.ts +12 -9
  130. package/src/core/modules/ai/services/core-ai-mcp.service.ts +206 -13
  131. package/src/core/modules/ai/services/core-ai-prompt-builder.service.ts +13 -6
  132. package/src/core/modules/ai/services/core-ai-user-setting.service.ts +85 -0
  133. package/src/core/modules/ai/services/core-ai.service.ts +134 -35
  134. package/src/core/modules/api-token/README.md +4 -2
  135. package/src/core/modules/better-auth/CUSTOMIZATION.md +1 -1
  136. package/src/core/modules/better-auth/INTEGRATION-CHECKLIST.md +7 -0
  137. package/src/core/modules/better-auth/README.md +32 -1
  138. package/src/core/modules/better-auth/better-auth.config.ts +12 -1
  139. package/src/core/modules/better-auth/core-better-auth-email-verification.service.ts +5 -2
  140. package/src/core/modules/better-auth/core-better-auth-path-guard.middleware.ts +85 -0
  141. package/src/core/modules/better-auth/core-better-auth-rate-limit.middleware.ts +5 -2
  142. package/src/core/modules/better-auth/core-better-auth-rate-limiter.service.ts +14 -7
  143. package/src/core/modules/better-auth/core-better-auth.module.ts +12 -2
  144. package/src/core/modules/better-auth/index.ts +1 -0
  145. package/src/core/modules/error-code/error-codes.ts +18 -0
  146. package/src/core/modules/sync/README.md +11 -1
  147. package/src/core/modules/sync/core-sync.service.ts +48 -3
  148. package/src/core/modules/tenant/INTEGRATION-CHECKLIST.md +12 -1
  149. package/src/core/modules/tenant/README.md +49 -3
  150. package/src/core/modules/tenant/core-tenant.guard.ts +18 -2
  151. package/src/core/modules/tenant/core-tenant.service.ts +287 -2
  152. package/src/test/test.helper.ts +17 -3
@@ -478,10 +478,36 @@ exports of `better-auth/plugins` but NOT in its runtime exports, verified on 1.7
478
478
  | What the controller handles | `CONTROLLER_HANDLED_PATHS` (same file) | the middleware and the Swagger helper read the same list — an explicit route always wins over a generated one |
479
479
 
480
480
  Pinned by `tests/better-auth-openapi.e2e-spec.ts` (404 against the assembled `ServerModule` for the
481
- canonical path AND six dot-segment spellings, sent raw with `http.request` because supertest and fetch
482
- normalise them away; mutation `openapi-plugin-routable` drops `serverOnlyPlugin()` and turns all seven
483
- red) and the "framework routes" cases in `tests/unit/swagger-helper.spec.ts`, which run against the
484
- REAL generator output rather than a fixture.
481
+ canonical path, and 400 or 404 for six dot-segment spellings, sent raw with `http.request` because supertest
482
+ and fetch normalise them away; mutation `openapi-plugin-routable` drops `serverOnlyPlugin()` and turns the
483
+ canonical case red — the spellings are refused by the path guard below either way) and the "framework routes"
484
+ cases in `tests/unit/swagger-helper.spec.ts`, which run against the REAL generator output rather than a fixture.
485
+
486
+ ### The path guard: the general answer to "the check reads a different path" (12.3.0)
487
+
488
+ The same mismatch reached past the open-api routes: the rate limiter skipped `/callback/../sign-in/email` as a
489
+ callback (its skip list matched the raw path) while Better-Auth ran it as a sign-in — no counter on sign-in at all.
490
+ `CoreBetterAuthPathGuardMiddleware` (`core-better-auth-path-guard.middleware.ts`) is therefore the FIRST middleware
491
+ under the base path, registered unconditionally in `CoreBetterAuthModule.configure()`, and refuses with 400
492
+ (`#LTNS_0305`) any path with a `.` / `..` segment (also `%2e`-encoded), a backslash, an encoded `/` or `\`, or a `#`
493
+ (Express routes the part before it, the forwarding to Better-Auth reads the whole string, so `sign-in/email#x` skipped
494
+ the controller and its e-mail verification check). No
495
+ route under the base path needs any of them. Behind it, the limiter still decides on `canonicalRequestPath()` and
496
+ matches its lists by whole segments (`pathContainsSegments()`), so it stays correct where the guard is not
497
+ registered.
498
+
499
+ | Rule | Why |
500
+ |---|---|
501
+ | A new check on the request path under the base path reads it AFTER the guard, never instead of it | the guard is what makes "the path as sent" and "the path Better-Auth routes" the same string |
502
+ | Do not widen the guard into a deny-list of routes | it refuses a SHAPE no route has; a route list is the §9 trap again |
503
+ | Match route lists by whole segments, not `includes()` | `includes('/session')` also matched `/sessions-export` |
504
+ | A middleware under the base path reads `req.originalUrl`, never `req.path` | Nest mounts it on `${basePath}/*path`, and Express moves the whole match into `req.baseUrl`: `req.path` is "/" there. The rate-limit middleware read it until 12.3.0, so every IAM request of a client shared one counter with the full limit and neither the skip list nor the strict sign-in limit applied over HTTP |
505
+ | Lower-case before comparing or keying | Express routes case-insensitively: `/sign-in/EMAIL` is the same sign-in and must share its counter |
506
+
507
+ Pinned by `tests/unit/better-auth-path-guard.spec.ts` (mutations `iam-path-guard-dot-segments-allowed`,
508
+ `iam-rate-limit-reads-raw-path`, `iam-rate-limit-case-sensitive`, `iam-rate-limit-middleware-reads-req-path`) and the
509
+ raw-request cases in `tests/better-auth-openapi.e2e-spec.ts` (mutations `iam-path-guard-not-registered`,
510
+ `iam-http-rate-limit-reads-req-path`), which also check the limit headers over HTTP.
485
511
 
486
512
  ## 10. Direct `api.*` calls must hand Better-Auth the request — or its CSRF protection does not run
487
513
 
@@ -574,5 +600,6 @@ security rules on every database.
574
600
  | Session cookie | Always the opaque session token — never the body JWT (§7) |
575
601
  | `account` reads / writes | Reads filter on `providerId` alone, never `issuer`. Writes set `issuer` only on better-auth 1.7.0–1.7.2, via the helper (§8) |
576
602
  | `openAPI()` plugin | Registered internally for `setupSwagger()`, kept off the router (`SERVER_ONLY`) unless the project registered it — never by a path check (§9) |
603
+ | Request path under the base path | `CoreBetterAuthPathGuardMiddleware` refuses a non-canonical path first; checks match whole segments of the canonical path (§9) |
577
604
  | Direct `api.*` calls | Hand Better-Auth the request (CSRF headers only) + `asResponse: false`, or its login-CSRF check is skipped (§10) |
578
605
  | SQL source | Better-Auth follows the users table; the framework reaches its data through `BetterAuthSqlStore`, ids stay strings (§11) |
@@ -306,7 +306,8 @@ This pattern is currently applied to:
306
306
  | BetterAuth 2FA Plugin | `betterAuth.twoFactor` | Boolean Shorthand | `appName: 'Nest Server'` |
307
307
  | BetterAuth Passkey Plugin | `betterAuth.passkey` | Boolean Shorthand | `rpName: 'Nest Server'` |
308
308
  | BetterAuth Cross-Subdomain Cookies | `betterAuth.crossSubDomainCookies` | Boolean Shorthand | `domain: auto (appUrl → baseUrl without api. prefix)` |
309
- | BetterAuth Disable Sign-Up | `betterAuth.emailAndPassword.disableSignUp` | Explicit Boolean | `false` (sign-up enabled). `true` also removes `POST /iam/sign-up/email` from the document `setupSwagger()` builds — the route answers `SIGNUP_DISABLED` to every caller then, so documenting it only misleads. The rule is `CoreBetterAuthService.isSignUpEnabled()`'s (`=== true`); a project controller extending `CoreBetterAuthController` that overrides `signUp` is covered, and so is the route Better-Auth generates for it. Implementation: `switchedOffBetterAuthPaths()` in `core-better-auth-openapi.helper.ts`, applied by `swagger.helper.ts` |
309
+ | BetterAuth Disable Sign-Up | `betterAuth.emailAndPassword.disableSignUp` | Explicit Boolean | `false` (sign-up enabled). `true` also removes `POST /iam/sign-up/email` from the document `setupSwagger()` builds — the route answers `SIGNUP_DISABLED` to every caller then, so documenting it only misleads. The rule is `CoreBetterAuthService.isSignUpEnabled()`'s (`=== true`); a project controller extending `CoreBetterAuthController` that overrides `signUp` is covered, and so is the route Better-Auth generates for it. **Since 12.3.0 it closes social sign-up too:** Better-Auth reads the flag for `/sign-up/email` only and decides a social sign-up per provider, so `buildSocialProviders()` hands every provider it as `disableSignUp` — a first social sign-in of an unknown user is refused (`error=signup_disabled` on the callback, 401 on `/sign-in/social` with an `idToken`), existing users keep signing in. `socialProviders.<name>.disableSignUp` is the deliberate exception per provider (`false` opens, `true` closes only that one); only a boolean counts there, any other value follows the global flag, so a string from `NEST_SERVER_CONFIG` cannot open a closed registration. Plugins a project adds through `betterAuth.options.plugins` are not covered. Pinned by `tests/unit/better-auth-social-sign-up.spec.ts` against the REAL `createBetterAuthInstance()`, including Better-Auth's own `/sign-in/social` handler (mutations `iam-social-sign-up-ignores-disable-sign-up`, `iam-social-sign-up-string-opens`). Implementation: `switchedOffBetterAuthPaths()` in `core-better-auth-openapi.helper.ts`, applied by `swagger.helper.ts`; `buildSocialProviders()` in `better-auth.config.ts` |
310
+ | BetterAuth Auto Sign-In After Verification | `betterAuth.emailVerification.autoSignInAfterVerification` | Explicit Boolean — **safe default** | **`false` since 12.3.0** (was `true`, against Better-Auth's own default). With it on, `GET /iam/verify-email` creates a session for the account the link belongs to in WHATEVER browser opens it. The link is a bearer credential that travels by mail: someone who signs up with their own address and forwards the unopened link has the recipient's browser signed in to their account, and what the recipient enters there (payment data, documents, messages) lands with them — login CSRF, the same class §10 of `.claude/rules/better-auth.md` closes for sign-in. Off, the user verifies and then signs in once. Matched with `=== true` in BOTH places that read it — `better-auth.config.ts` (what Better-Auth receives) and `CoreBetterAuthEmailVerificationService.shouldAutoSignIn()` (what a project asks) — so a truthy non-boolean (the string `"true"` in `NEST_SERVER_CONFIG`; `NSC__*` already coerces `true`) cannot switch it on, and the two cannot disagree. Pinned by `tests/unit/better-auth-auto-sign-in.spec.ts` against the REAL `createBetterAuthInstance()` (mutations `iam-auto-sign-in-after-verification-default-on`, `iam-auto-sign-in-service-default-on`) |
310
311
  | BetterAuth Native Password Reset | `betterAuth.emailAndPassword.passwordReset` | Explicit Boolean | **`true` — ON by default, and there is no other off switch.** Better-Auth treats the PRESENCE of an `emailAndPassword.sendResetPassword` hook as the enable flag, and `CoreBetterAuthModule` always injects one (delegating to `CoreBetterAuthEmailVerificationService.sendPasswordResetEmail()`). So `POST /iam/request-password-reset` is a live, **unauthenticated**, token-minting, mail-sending endpoint on every deployment — before 11.36.1 it answered `RESET_PASSWORD_DISABLED` because no hook was wired. Set `false` to withhold the hook and restore that refusal, for deployments whose reset policy is support-mediated or SSO-primary. **Two things bound the abuse and both need checking:** a per-ADDRESS cooldown in the mailer (reuses `emailVerification.resendCooldownSeconds`, own namespace so a pending verification mail cannot block a reset), and the IP-axis `betterAuth.rateLimit` in front of the route — which is OFF unless configured. `/request-password-reset` is in `strictEndpoints`, so it gets the halved limit. Implementation: `better-auth.config.ts` (graft), `core-better-auth-email-verification.service.ts` (delivery) **Swagger (11.42.9):** `false` also removes `/request-password-reset`, `/reset-password` and `/reset-password/{token}` from the document `setupSwagger()` builds — without the hook no token can be minted, so none of them can succeed |
311
312
  | BetterAuth Password-Reset Brevo Template | `betterAuth.emailVerification.passwordResetBrevoTemplateId` | Presence Implies Enabled | `undefined` → SMTP/EJS path. When set, the reset mail goes out through the Brevo transactional API with that template id. **Deliberately does NOT fall back to `brevoTemplateId`**: that one is the VERIFICATION mail, and reusing it would tell somebody who asked to reset their password to confirm their address instead. A Brevo send that resolves to `null` (its way of reporting failure unless `brevo.throwOnError` is set) falls THROUGH to SMTP rather than returning, so an outage does not leave a locked-out user with no mail at all. Template variables: `name`, `link`, `appName` |
312
313
  | BetterAuth Revoke Sessions on Password Reset | `betterAuth.emailAndPassword.revokeSessionsOnPasswordReset` | Explicit Boolean | `false` (existing sessions survive a reset). Forwarded to Better-Auth's native flag, which honours it on **all three** reset routes (password reset, email-OTP, phone-number). **Off by default because it is a behaviour change for an existing deployment** — after a reset the user is signed out everywhere, including on the devices they still hold. Turn it on where a reset is what somebody reaches for after a suspected takeover: otherwise the attacker keeps their session and the new password changes nothing for them. Matched with `=== true`, so a truthy-but-not-`true` value arriving as JSON through `NSC__*` / `NEST_SERVER_CONFIG` does not silently enable a sign-out-everywhere behaviour. **Prefer the named field over `betterAuth.options`**: it is validated (`=== true`), typed and discoverable. Until 11.36.1 the reason was harsher — `config.options` was spread SHALLOWLY over the resolved config (only `advanced` was deep-merged), so an `options.emailAndPassword` REPLACED the whole block including the scrypt `password.hash` / `password.verify` pair the framework installs, and every credential in the database stopped verifying, at runtime and without a boot error. Since 11.36.1 `emailAndPassword` is deep-merged too, with `password` merged key-by-key on top of the framework's pair (an explicit override still wins; an explicitly-`undefined` half is ignored, because Better-Auth resolves `password?.hash || hashPassword` and would otherwise switch hasher for writes while scrypt still handled reads). That merge is pinned against the REAL `createBetterAuthInstance()` by `tests/unit/better-auth-password-reset-wiring.spec.ts`, with registered mutation `betterauth-emailandpassword-shallow-merge` as its evidence. Implementation: `better-auth.config.ts` (`emailAndPassword` block) |
@@ -321,10 +322,10 @@ This pattern is currently applied to:
321
322
  | Translate Response Interceptor | `security.translateResponseInterceptor` | Boolean Shorthand | `true` (enabled) |
322
323
  | Mongoose CastError Filter | `security.mongooseCastErrorFilter` | Explicit Boolean — **safe default** | **`true` since 11.42.16.** `MongooseCastErrorFilter`, registered by `CoreModule` as `APP_FILTER` (so `main.ts` and `Test.createTestingModule()` setups need nothing). A malformed id reached Mongoose and its `CastError` — not an `HttpException` — escaped every `@Catch(HttpException)` filter, so `GET /users/<malformed-id>` and every other `:id` route answered **500**. The filter decides by WHERE the failing value came from: a route parameter or a top-level GraphQL argument → **404** `ErrorCode.RESOURCE_NOT_FOUND` (answered like an unknown id); the query string, an update or filter body, or a nested GraphQL input → **400** `ErrorCode.INVALID_FIELD_FORMAT [<path>]`; a value the request does not contain (a broken stored id, a server-computed value) → **stays a 500**, with Nest's own body and log line (context `ExceptionsHandler`), because that is a data or code defect monitoring must keep seeing — relabelling it as a client error is the mistake the refusal tests pin (mutations `cast-error-server-value-relabelled-*`). Only primitives and arrays of primitives (`$in`) are matched: an object cast as a whole yields no candidates, so its inner strings cannot match the body by coincidence. Never sends the Mongoose message (it names the model). REST bodies use the `HttpExceptionLogFilter` shape (`{ ...exception }`). A project's own catch-all filter via `app.useGlobalFilters()` is consulted first and wins. Covers casts Mongoose raises while running a QUERY or an UPDATE (`findById`, filters, `findByIdAndUpdate` — `CrudService.update()`). NOT covered, both stay a 500: a malformed id in a document being CREATED (`save()` / `create()` / `insertMany()` — `CrudService.create()`), which Mongoose reports as a `ValidationError` wrapping the CastError (validate in the input: `validator: () => [IsMongoId()]`); and a `BSONError` from `new Types.ObjectId(bad)`, which carries no value (check the id in the service, `CoreFileService.isMalformedFileId()`). `false` restores the 500. Implementation: `common/filters/mongoose-cast-error.filter.ts` |
323
324
  | Secret Fields Removal | `security.secretFields` | Array | `['password', 'verificationToken', ...]` |
324
- | Data Sources | `database` | Explicit Value — absent = today's `mongoose` config | **Absent → the `mongoose` configuration is the only data source, exactly as before; nothing SQL is loaded or installed.** A URL string (`'postgres://…'`) sets the default source (driver from the scheme, `sqlEngine` defaults to `typeorm`; `kysely` and `drizzle` are the alternatives — optional peers, each with `pg`); an object adds `ownerUrl` (default source), `sources` (name → URL or `{ url, ownerUrl, sqlEngine }`) and per-model exceptions (`models`); `false` means no database. Precedence for a model: `database.models` > the `dataSource` of a `CorePersistenceModule.forFeature()` definition > `@PersistedModel({ dataSource })` (read from the definition's `model:` class, otherwise from the decorated class named like the model; two such classes naming different sources refuse to guess) > default. When `database` sets a default and the project ALSO configures `mongoose` explicitly, that MongoDB becomes the source `mongoose` — only the project's own `mongoose` counts, because `CoreModule.forRoot()` always merges a fallback URI. **Since phase 1 (DEV-3829) PostgreSQL sources are wired**: only models registered with `CorePersistenceModule.forFeature()` are routed — **since phase 2 (DEV-3830) that includes the core's own models**: the user model (the reference `UserModule`), tenant memberships and API tokens, whose services switch to the routed store (a service that only received `@InjectModel()` follows its model's store; the Mongoose model of a model routed to SQL refuses every data access with a named error, so a direct `mainDbModel` call cannot split a model's data). **Since phase 3 (DEV-3831) Better-Auth follows the user model**: with the user model (table `users`) on a SQL source, Better-Auth runs its built-in Kysely adapter on that source's application pool — ONE `users` row per user shared with the user model (Better-Auth's own columns `name`, `email_verified`, `image` beside the framework's; its required ones are added nullable, so a row the user model writes alone stays valid), snake_case tables (`session`, `account`, `verification`, `jwks`, `two_factor`, `passkey`), ObjectId-hex ids. Its schema is applied as the OWNER at boot, under the same schema lock and grants as the framework's tables; without `ownerUrl` the application role only verifies and the boot stops while Better-Auth's migrations are pending. The framework's own reads and writes of Better-Auth's data follow it (session lookup by token, token service, JWKS, passkey challenge mappings — as Better-Auth verification values —, the e-mail-verified hook, user mapper, system setup, migration status — counted in SQL —, the MCP OAuth subject's roles); the MongoDB boot steps (indices, account-issuer backfill) are skipped there. Nothing is copied from MongoDB: a project that moves its users brings them over itself. **Since phase 4 (DEV-3832) the remaining core persistence follows too**: the AI module's eleven models and the three MCP OAuth stores (clients, codes, refresh tokens) are registered through `CorePersistenceModule.forFeature()` and run on their routed store (one code path; an upsert is update-then-insert with a retry on a duplicate, `sum()` replaces the budget aggregation, `find(…, { exclude })` the `-field` projection); the S3 and filesystem file metadata are two framework models (`CoreS3File`, `CoreFilesystemFile`, tables `s3_files` / `filesystem_files`) read and written through `fileMetadataCollection()` by the file service, the TUS hand-off and the Hub — GridFS stays MongoDB-only. A collection name with a hyphen becomes a table with an underscore. A TTL (`expires`, `index: { expireAfterSeconds }`) is a plain index on SQL; an **expiry sweep** (`scheduleExpirySweep()`, every 15 min, one replica per interval through a lease in the default SQL source's `lt_locks`, fail-open) deletes the expired rows of every routed TTL model, and — with Better-Auth on SQL — expired sessions and verification values. Nothing relies on it for correctness: every reader checks the expiry (an MCP authorization code older than ten minutes is refused on read on both databases). MongoDB keeps its TTL indexes and gets no sweep. The framework's leases (system-setup claim, cron, migrations) live in the default source: on MongoDB in the 12.0.0 documents (a rolling deploy with older replicas shares them), on SQL in `lt_locks`, namespaced, swept an hour after expiry. With `healthCheck.configs.database` every SQL source answers as `<key>:<source>`; `createMigrationStore(<owner URL>)` keeps the migration state in `lt_migrations` with an advisory run lock, on the first SQL engine installed (the CLI cannot read `database.sqlEngine`), and the Hub refuses to run migrations while that table is empty and the MongoDB collection is not (a `migrate.js` still writing MongoDB); the Hub's Persistence panel shows the routing. a SQL model's table is migrated as the OWNER (`ownerUrl`) when its store is created — without `ownerUrl` the application role only verifies and the boot stops while changes are pending; ONE owner connection per source, released once the application is bootstrapped — and the boot refuses an application role that is superuser, has `BYPASSRLS`, owns (or inherits the owner of) a framework table or may `TRUNCATE` it. Two roles in every environment (plan §3.9). Changes the framework never applies on its own (type change, new unique index, rename collision) stop the boot with the suggested statements; `migrate create <name> --sql` + `runSqlMigration()` apply them after review. **Since phase 5 (DEV-3833, 12.1.0) MongoDB is optional**: `mongoose`, `@nestjs/mongoose` and `mongodb` are optional peers, loaded through `common/persistence/mongo/mongo-packages.ts`; `CoreModule` connects MongoDB only when a source uses it (`usesMongoDb()` — `mongoose` configured explicitly, `database` naming MongoDB, or `database` absent), otherwise `@InjectConnection()` receives `null` and a model token without a connection is a stand-in that refuses data access. A configured MongoDB feature without the packages fails the boot with `MongoPackagesMissingError`. `database: false` runs a service without any database: a registered model's store refuses with the reason, Better-Auth is refused at boot. Proven by `pnpm run check:without-mongodb` (dist, packages hidden) and `check:without-mongodb:package` (the tarball installed without them, publish path). **Since phase 6 (DEV-3848) MySQL 8.4 and MariaDB 11.8 sources are wired** (`mysql://`, `mariadb://` — the scheme must name the server the URL reaches): `mysql2` is an optional peer beside the engine, all three engines run on one pool the framework creates (strict session with backslash escapes, UTC), `MysqlDataStore` writes the statements, the owner grants the application account `SELECT, INSERT, UPDATE, DELETE` on the database once and the boot refuses an application account that may alter, drop, index, trigger or grant; leases, migration state (`createMigrationStore()` / `runSqlMigration()` under `GET_LOCK`), the expiry sweep, health check and Hub work there. **Neither database has row-level security**: tenant isolation is the store's, the boot warns once per source, and native / raw access on a tenant table must filter by tenant itself. **Since 12.1.1 (DEV-3904) Better-Auth runs there too**: its Kysely adapter on the source's `mysql2` pool (the promise wrapper — Better-Auth builds `MysqlDialect` from it), its migrations as the owner under `GET_LOCK`, with the database's default collation switched to `utf8mb4_bin` while it creates a table and restored (`withFrameworkDefaultCollation()`; only on such a run and with a 5 s lock wait, because `ALTER DATABASE` locks every table) — Better-Auth names no collation, and MariaDB refuses a foreign key to `users.id` across collations; the database-level grant covers its tables. 12.1.0 refused it at boot. An indexed text field is `varchar(255)` (longer: 400); a DDL run is not transactional. Still refused with a named `DataSourceConfigError`: a second MongoDB source, and an `ownerUrl` without `url` — what `NSC__DATABASE__OWNER_URL` leaves of a `database` given as a URL string, because the environment merge replaces the string with an object (write `database: { url }`, or set `NSC__DATABASE__URL` too). An update path the model does not declare is dropped on SQL as by MongoDB's strict mode (`CrudService.update()` adds `updatedBy` to every update with a current user). URLs appear in errors and logs as scheme + host only. Implementation: `common/persistence/data-source.config.ts`, `data-source.runtime.ts`, `sql/` (plan: `.claude/plans/db-agnostic/PLAN.md` §3.9) |
325
- | Multi-Tenancy | `multiTenancy` | Presence Implies Enabled | **`excludeSchemas` is an OFF SWITCH for isolation, per model** — a listed schema gets no tenant filter at all; since 11.35.0 the plugin WARNS once per model when the excluded schema declares `tenantId` (i.e. was built for isolation). The framework's own docs recommended `['User', 'Session']` until then; that is withdrawn — it is only right for the global-user model. Since 11.35.0 GraphQL operations over the WEBSOCKET also run inside a `RequestContext` (`CoreModule` installs a context-aware `execute`/`subscribe` pair inside `subscriptions`, where `ApolloDriver` forwards it): the tenant comes from the handshake header validated against an active membership, else from the subscriber's memberships, and an unresolvable tenant leaves the safety net to refuse the read rather than returning everything. `headerName: 'x-tenant-id'`, `membershipModel: 'TenantMember'`, `adminBypass: true`, `excludeSchemas: []`, `roleHierarchy: { member: 1, manager: 2, owner: 3 }`, `cacheTtlMs: 30000` (0 disables, process-local). System roles (`S_EVERYONE`, `S_USER`, `S_VERIFIED`) are checked as OR alternatives before real roles; method-level system roles take precedence; membership validated for context when system role grants access + header present. Hierarchy roles use level comparison, normal roles use exact match. Use `DefaultHR` or `createHierarchyRoles()` for type-safe role constants. Bypass: `RequestContext.runWithBypassTenantGuard()`. Cache invalidation: `invalidateUser(userId)` / `invalidateAll()` are **instance** methods on the singleton `CoreTenantGuard` — inject it and call `this.tenantGuard?.invalidateUser(userId)`, never `CoreTenantGuard.invalidateUser(...)` (there is no static). With `redis` configured, both additionally BROADCAST the invalidation to every replica (`<keyPrefix>:tenant-cache:invalidate` pub/sub); without Redis they clear the local process only, so other replicas stay stale until `cacheTtlMs`. A received broadcast clears locally without re-publishing. **`isTenantActive` (11.42.0)**: optional hook `(tenantId, { connection, store }) => boolean \| Promise<boolean>`, absent = every tenant active (no change). `store(modelName)` (12.x, db-agnostic) is the data store of a model registered with `CorePersistenceModule.forFeature()`, wherever `database` routes it, and THROWS for any other model — an `undefined` would read as "active" in a hook written with `?.` and open every deactivated tenant. Asked AFTER the membership check on every path that establishes a tenant: 403 on header paths and for tenant API tokens, no enrichment on `S_EVERYONE`, dropped from the header-less tenant list, no tenant for a NEW WebSocket subscription, and since 11.42.3 an OPEN one is closed with 4403 on `invalidateTenant()` (or at its next event once `graphQl.subscriptionRevalidationMs` has passed — see the GraphQL Subscription Re-check row); an admin under `adminBypass` is exempt (someone must be able to switch it back on). Only `false` deactivates. Cached for `cacheTtlMs`; `invalidateTenant(tenantId)` clears and broadcasts (`{ scope: 'tenant' }`). A function, so `config.env.ts` only — not reachable through `NSC__*`. **`adminBypass: false` (11.42.0)** additionally withholds two things that went around it: `CoreUserService.update()` refuses changing another account's e-mail or password (`assertCredentialChangeAllowed()`, administrator targets included — promote-then-change — system work without a current user exempt), and the AI tool registry grants no ADMIN bypass |
325
+ | Data Sources | `database` | Explicit Value — absent = today's `mongoose` config | **Absent → the `mongoose` configuration is the only data source, exactly as before; nothing SQL is loaded or installed.** A URL string (`'postgres://…'`) sets the default source (driver from the scheme, `sqlEngine` defaults to `typeorm`; `kysely` and `drizzle` are the alternatives — optional peers, each with `pg`); an object adds `ownerUrl` (default source), `sources` (name → URL or `{ url, ownerUrl, sqlEngine }`) and per-model exceptions (`models`); `false` means no database. Precedence for a model: `database.models` > the `dataSource` of a `CorePersistenceModule.forFeature()` definition > `@PersistedModel({ dataSource })` (read from the definition's `model:` class, otherwise from the decorated class named like the model; two such classes naming different sources refuse to guess) > default. When `database` sets a default and the project ALSO configures `mongoose` explicitly, that MongoDB becomes the source `mongoose` — only the project's own `mongoose` counts, because `CoreModule.forRoot()` always merges a fallback URI. **Since phase 1 (DEV-3829) PostgreSQL sources are wired**: only models registered with `CorePersistenceModule.forFeature()` are routed — **since phase 2 (DEV-3830) that includes the core's own models**: the user model (the reference `UserModule`), tenant memberships and API tokens, whose services switch to the routed store (a service that only received `@InjectModel()` follows its model's store; the Mongoose model of a model routed to SQL refuses every data access with a named error, so a direct `mainDbModel` call cannot split a model's data). **Since phase 3 (DEV-3831) Better-Auth follows the user model**: with the user model (table `users`) on a SQL source, Better-Auth runs its built-in Kysely adapter on that source's application pool — ONE `users` row per user shared with the user model (Better-Auth's own columns `name`, `email_verified`, `image` beside the framework's; its required ones are added nullable, so a row the user model writes alone stays valid), snake_case tables (`session`, `account`, `verification`, `jwks`, `two_factor`, `passkey`), ObjectId-hex ids. Its schema is applied as the OWNER at boot, under the same schema lock and grants as the framework's tables; without `ownerUrl` the application role only verifies and the boot stops while Better-Auth's migrations are pending. The framework's own reads and writes of Better-Auth's data follow it (session lookup by token, token service, JWKS, passkey challenge mappings — as Better-Auth verification values —, the e-mail-verified hook, user mapper, system setup, migration status — counted in SQL —, the MCP OAuth subject's roles); the MongoDB boot steps (indices, account-issuer backfill) are skipped there. Nothing is copied from MongoDB: a project that moves its users brings them over itself. **Since phase 4 (DEV-3832) the remaining core persistence follows too**: the AI module's eleven models and the three MCP OAuth stores (clients, codes, refresh tokens) are registered through `CorePersistenceModule.forFeature()` and run on their routed store (one code path; an upsert is update-then-insert with a retry on a duplicate, `sum()` replaces the budget aggregation, `find(…, { exclude })` the `-field` projection); the S3 and filesystem file metadata are two framework models (`CoreS3File`, `CoreFilesystemFile`, tables `s3_files` / `filesystem_files`) read and written through `fileMetadataCollection()` by the file service, the TUS hand-off and the Hub — GridFS stays MongoDB-only. A collection name with a hyphen becomes a table with an underscore. A TTL (`expires`, `index: { expireAfterSeconds }`) is a plain index on SQL; an **expiry sweep** (`scheduleExpirySweep()`, every 15 min, one replica per interval through a lease in the default SQL source's `lt_locks`, fail-open) deletes the expired rows of every routed TTL model, and — with Better-Auth on SQL — expired sessions and verification values. Nothing relies on it for correctness: every reader checks the expiry (an MCP authorization code older than ten minutes is refused on read on both databases). MongoDB keeps its TTL indexes and gets no sweep. The framework's leases (system-setup claim, cron, migrations) live in the default source: on MongoDB in the 12.0.0 documents (a rolling deploy with older replicas shares them), on SQL in `lt_locks`, namespaced, swept an hour after expiry. With `healthCheck.configs.database` every SQL source answers as `<key>:<source>`; `createMigrationStore(<owner URL>)` keeps the migration state in `lt_migrations` with an advisory run lock, on the first SQL engine installed (the CLI cannot read `database.sqlEngine`), and the Hub refuses to run migrations while that table is empty and the MongoDB collection is not (a `migrate.js` still writing MongoDB); the Hub's Persistence panel shows the routing. a SQL model's table is migrated as the OWNER (`ownerUrl`) when its store is created — without `ownerUrl` the application role only verifies and the boot stops while changes are pending; ONE owner connection per source, released once the application is bootstrapped — and the boot refuses an application role that is superuser, has `BYPASSRLS`, owns (or inherits the owner of) a framework table or may `TRUNCATE` it. Two roles in every environment (plan §3.9). Changes the framework never applies on its own (type change, new unique index, rename collision) stop the boot with the suggested statements; `migrate create <name> --sql` + `runSqlMigration()` apply them after review. **Since phase 5 (DEV-3833, 12.1.0) MongoDB is optional**: `mongoose`, `@nestjs/mongoose` and `mongodb` are optional peers, loaded through `common/persistence/mongo/mongo-packages.ts`; `CoreModule` connects MongoDB only when a source uses it (`usesMongoDb()` — `mongoose` configured explicitly, `database` naming MongoDB, or `database` absent), otherwise `@InjectConnection()` receives `null` and a model token without a connection is a stand-in that refuses data access. A configured MongoDB feature without the packages fails the boot with `MongoPackagesMissingError`. `database: false` runs a service without any database: a registered model's store refuses with the reason, Better-Auth is refused at boot. Proven by `pnpm run check:without-mongodb` (dist, packages hidden) and `check:without-mongodb:package` (the tarball installed without them, publish path). **Since phase 6 (DEV-3848) MySQL 8.4 and MariaDB 11.8 sources are wired** (`mysql://`, `mariadb://` — the scheme must name the server the URL reaches): `mysql2` is an optional peer beside the engine, all three engines run on one pool the framework creates (strict session with backslash escapes, UTC), `MysqlDataStore` writes the statements, the owner grants the application account `SELECT, INSERT, UPDATE, DELETE` on the database once and the boot refuses an application account that may alter, drop, index, trigger or grant; leases, migration state (`createMigrationStore()` / `runSqlMigration()` under `GET_LOCK`), the expiry sweep, health check and Hub work there. **Neither database has row-level security**: tenant isolation is the store's, the boot warns once per source, and native / raw access on a tenant table must filter by tenant itself. **Since 12.1.1 (DEV-3904) Better-Auth runs there too**: its Kysely adapter on the source's `mysql2` pool (the promise wrapper — Better-Auth builds `MysqlDialect` from it), its migrations as the owner under `GET_LOCK`, with the database's default collation switched to `utf8mb4_bin` while it creates a table and restored (`withFrameworkDefaultCollation()`; only on such a run and with a 5 s lock wait, because `ALTER DATABASE` locks every table) — Better-Auth names no collation, and MariaDB refuses a foreign key to `users.id` across collations; the database-level grant covers its tables. 12.1.0 refused it at boot. An indexed text field is `varchar(255)` (longer: 400); a DDL run is not transactional. Still refused with a named `DataSourceConfigError`: a second MongoDB source, and an `ownerUrl` without `url` — what `NSC__DATABASE__OWNER_URL` leaves of a `database` given as a URL string, because the environment merge replaces the string with an object (write `database: { url }`, or set `NSC__DATABASE__URL` too). An update path the model does not declare is dropped on SQL as by MongoDB's strict mode (`CrudService.update()` adds `updatedBy` to every update with a current user). URLs appear in errors and logs as scheme + host only. Implementation: `common/persistence/data-source.config.ts`, `data-source.runtime.ts`, `sql/` (db-agnostic plan §3.9) |
326
+ | Multi-Tenancy | `multiTenancy` | Presence Implies Enabled | **`excludeSchemas` is an OFF SWITCH for isolation, per model** — a listed schema gets no tenant filter at all; since 11.35.0 the plugin WARNS once per model when the excluded schema declares `tenantId` (i.e. was built for isolation). The framework's own docs recommended `['User', 'Session']` until then; that is withdrawn — it is only right for the global-user model. Since 11.35.0 GraphQL operations over the WEBSOCKET also run inside a `RequestContext` (`CoreModule` installs a context-aware `execute`/`subscribe` pair inside `subscriptions`, where `ApolloDriver` forwards it): the tenant comes from the handshake header validated against an active membership, else from the subscriber's memberships, and an unresolvable tenant leaves the safety net to refuse the read rather than returning everything. `headerName: 'x-tenant-id'`, `membershipModel: 'TenantMember'`, `adminBypass: true`, `excludeSchemas: []`, `roleHierarchy: { member: 1, manager: 2, owner: 3 }`, `cacheTtlMs: 30000` (0 disables, process-local). System roles (`S_EVERYONE`, `S_USER`, `S_VERIFIED`) are checked as OR alternatives before real roles; method-level system roles take precedence; membership validated for context when system role grants access + header present. Hierarchy roles use level comparison, normal roles use exact match. Use `DefaultHR` or `createHierarchyRoles()` for type-safe role constants. Bypass: `RequestContext.runWithBypassTenantGuard()`. Cache invalidation: `invalidateUser(userId)` / `invalidateAll()` are **instance** methods on the singleton `CoreTenantGuard` — inject it and call `this.tenantGuard?.invalidateUser(userId)`, never `CoreTenantGuard.invalidateUser(...)` (there is no static). With `redis` configured, both additionally BROADCAST the invalidation to every replica (`<keyPrefix>:tenant-cache:invalidate` pub/sub); without Redis they clear the local process only, so other replicas stay stale until `cacheTtlMs`. A received broadcast clears locally without re-publishing. **`isTenantActive` (11.42.0)**: optional hook `(tenantId, { connection, store }) => boolean \| Promise<boolean>`, absent = every tenant active (no change). `store(modelName)` (12.x, db-agnostic) is the data store of a model registered with `CorePersistenceModule.forFeature()`, wherever `database` routes it, and THROWS for any other model — an `undefined` would read as "active" in a hook written with `?.` and open every deactivated tenant. Asked AFTER the membership check on every path that establishes a tenant: 403 on header paths and for tenant API tokens, no enrichment on `S_EVERYONE`, dropped from the header-less tenant list, no tenant for a NEW WebSocket subscription, and since 11.42.3 an OPEN one is closed with 4403 on `invalidateTenant()` (or at its next event once `graphQl.subscriptionRevalidationMs` has passed — see the GraphQL Subscription Re-check row); an admin under `adminBypass` is exempt (someone must be able to switch it back on). Only `false` deactivates. Cached for `cacheTtlMs`; `invalidateTenant(tenantId)` clears and broadcasts (`{ scope: 'tenant' }`) — since 12.3.0 together with the tenant's cached memberships and every cached tenant list holding it, so memberships removed without `invalidateUser()` (a deleted tenant) stop counting at once rather than after `cacheTtlMs` (a tenant switched off through `isTenantActive` was already refused at once, its answer being cleared). **Removing a tenant (12.3.0)**: `CoreTenantService.purgeTenantData(tenantId, { dryRun?, exclude? })` first ends every way in — the memberships (`deleteAllMembers()`) and the tenant's API tokens, which need no member — then deletes, in batches of 1000 ids, every registered model with a `tenantId` path (MongoDB and SQL), the core references without one (the AI settings with `scope: 'tenant'`) and the AI connections — one only this tenant could use is deleted, from a shared one the tenant is removed (an empty `tenantIds` means every tenant). `excludeSchemas` and `exclude` are left out, so are users and files; the protected `purgeTenantRecords()` is where a project adds its own references. A function, so `config.env.ts` only — not reachable through `NSC__*`. **`adminBypass: false` (11.42.0)** additionally withholds two things that went around it: `CoreUserService.update()` refuses changing another account's e-mail or password (`assertCredentialChangeAllowed()`, administrator targets included — promote-then-change — system work without a current user exempt), and the AI tool registry grants no ADMIN bypass |
326
327
  | GraphQL Subscription Re-check | `graphQl.subscriptionRevalidationMs` | Numeric — `0` = STRICTEST, `false` = off, invalid → default (a fifth shape: Family C's "invalid never means unbounded", but `0` asks for MORE checking, not less) | **30000 since 11.42.3.** Before, a WebSocket was authorized once, at the handshake, and every event and operation on it ran on that snapshot until the client reconnected. Every connection a `CoreModule` `onConnect` accepts is now registered (`registerWsConnection()`) and re-checked — at once when an invalidation names it (`CoreTenantGuard.invalidateUser()` / `invalidateTenant()` / `invalidateAll()`, `CoreUserService.setRoles()` and role/verification `update()`s, the legacy password reset, and Better-Auth deleting a session through `wsSessionRevocationPlugin()`), and otherwise before the next event or operation once the last check is older than this value. The check re-runs the handshake's own authentication (session store, Better-Auth JWT signature/expiry, or for legacy tokens `CoreAuthService.verifyJwt()` — signature/expiry, verified on the WebSocket since 11.42.3 — plus the device binding) and the tenant resolution; any difference in user id, roles, verification state or tenant scope closes the socket with **4403**, which the graphql-ws client retries — the user continues with current rights or is refused at the handshake. `0` re-checks on every event and operation (one session lookup each); `false` switches only the TIME-based check off, invalidations still apply. Process-local registry: an invalidation reaches other replicas only where a Redis broadcast carries it — the tenant guard's (memberships, tenants) and, since 12.1.1, the Better-Auth user mapper's (`invalidateUserCache()`: roles and verification of IAM users); everything else is bounded by the interval. A project that replaces `onConnect` through `graphQl.driver.subscriptions` must call `registerWsConnection()` itself to keep this. Implementation: `common/helpers/graphql-ws-connection.helper.ts` |
327
- | API Tokens | `apiTokens` | Boolean Shorthand + Presence Implies Enabled — absent = off | `prefix: 'ltt'`, `scopes: []` (vocabulary; empty = no token creatable, boot warning), `manageRole`: highest hierarchy role, `maxAssertionLifetimeSeconds: 900` (invalid → default, never unbounded — Family C), `rateLimit: { max: 600, windowSeconds: 60 }` per token (**on by default**, `false` disables; Redis-shared when configured), `userTokens: true`, `tenantTokens: true` (effective only with `multiTenancy`), `encryptionKey` → `SECRETS_ENCRYPTION_KEY` → dev default (boot FAILS in production/staging). Top-level, NOT under `multiTenancy`: user tokens must work without it. **Deny by default**: every guard refuses a token on a route without `@ApiTokenScopes()`, public routes included, via ONE shared function (`enforceApiTokenRoute`) called BEFORE each guard's public-route shortcut. USER tokens act as their user with global roles REMOVED (no admin bypass); TENANT tokens act with the lowest hierarchy role in their own tenant, and a route guarded ONLY by `S_SELF` / `S_CREATOR` refuses them (a tenant token is nobody's self — skipping those roles would grant for any target). A tenant token depends on no member, so it outlives an off-boarded or deleted tenant until the project calls `deleteAllForTenant()`. The boot refuses a hierarchy in which that lowest role reaches `manageRole`. A prefixed credential that fails answers 401 on every route (not anonymous); `CoreBetterAuthMiddleware` skips prefixed credentials entirely, cookie fallback included. A password reset that ends the user's sessions ends their USER tokens too (legacy reset always; IAM reset while `betterAuth.emailAndPassword.revokeSessionsOnPasswordReset` is on), wired through `core-api-token.registry.ts` so neither reset path imports the optional module. Implementation: `src/core/modules/api-token/` |
328
+ | API Tokens | `apiTokens` | Boolean Shorthand + Presence Implies Enabled — absent = off | `prefix: 'ltt'`, `scopes: []` (vocabulary; empty = no token creatable, boot warning), `manageRole`: highest hierarchy role, `maxAssertionLifetimeSeconds: 900` (invalid → default, never unbounded — Family C), `rateLimit: { max: 600, windowSeconds: 60 }` per token (**on by default**, `false` disables; Redis-shared when configured), `userTokens: true`, `tenantTokens: true` (effective only with `multiTenancy`), `encryptionKey` → `SECRETS_ENCRYPTION_KEY` → dev default (boot FAILS in production/staging). Top-level, NOT under `multiTenancy`: user tokens must work without it. **Deny by default**: every guard refuses a token on a route without `@ApiTokenScopes()`, public routes included, via ONE shared function (`enforceApiTokenRoute`) called BEFORE each guard's public-route shortcut. USER tokens act as their user with global roles REMOVED (no admin bypass); TENANT tokens act with the lowest hierarchy role in their own tenant, and a route guarded ONLY by `S_SELF` / `S_CREATOR` refuses them (a tenant token is nobody's self — skipping those roles would grant for any target). A tenant token depends on no member, so it outlives an off-boarded or deleted tenant until the project calls `deleteAllForTenant()` or `CoreTenantService.purgeTenantData()`. The boot refuses a hierarchy in which that lowest role reaches `manageRole`. A prefixed credential that fails answers 401 on every route (not anonymous); `CoreBetterAuthMiddleware` skips prefixed credentials entirely, cookie fallback included. A password reset that ends the user's sessions ends their USER tokens too (legacy reset always; IAM reset while `betterAuth.emailAndPassword.revokeSessionsOnPasswordReset` is on), wired through `core-api-token.registry.ts` so neither reset path imports the optional module. Implementation: `src/core/modules/api-token/` |
328
329
  | Offline Sync | `sync` | Boolean Shorthand + Presence Implies Enabled — absent = off | **Absent → nothing registered**: no route, no infrastructure model, no listener on the write paths. `true` / `{}` enables `GET /sync/{model}` (pull) and `POST /sync/{model}` (push) for every model whose CrudService carries `@SyncService({ model, createInput, updateInput })` and whose model is declared with `@PersistedModel({ sync: { roles, strategy } })`. Defaults: `path: 'sync'`, `pull: { defaultLimit: 200, maxLimit: 1000 (ceiling 1000), maxBytes: 1048576 }`, `push: { maxItems: 100 }`, `retention: { mutationsDays: 30, tombstonesDays: 90 }`, `hints: { debounceMs: 250 }`, `rateLimit: { pull: { max: 120, windowSeconds: 60 }, push: { max: 60, windowSeconds: 60 } }` per user (`false` switches both or one off; Redis-shared when configured). `cursorSecret` → `SECRETS_ENCRYPTION_KEY` → development default (boot FAILS in production/staging); changing it answers every cursor `410 invalid`. `pull.windowSeconds` (MongoDB only) overrides the derived window W: replica set or sharded — the server's `transactionLifetimeLimitSeconds` (60 when unreadable) + 30, standalone — 30; it must cover the longest time a write takes from its stamp until it is visible, a smaller one loses changes for good. **Operation roles are the model's** (`sync.roles.pull/create/update/delete`): the roles a project puts on its own routes never reach `/sync`, and an operation without roles is ADMIN only (boot warning). Every pull and push runs through the model's CrudService (`process()`, `securityCheck()`, tenant policy, RLS). Without `X-Tenant-Id` a request spans the caller's memberships. Cookie pushes need `Content-Type: application/json`; while cookies are in use `Sec-Fetch-Site: cross-site` and an untrusted `Origin` answer 403. API tokens are refused unless a project controller releases a scope. Error codes `LTNS_0700`–`LTNS_0799`. **Hints (12.x, DEV-3902)**: `GET /sync/hints` (Server-Sent Events, event `change`, `?models=` narrows) and the GraphQL subscription `syncHint(models)` tell a client "pull now" — payload `{ model, at }` only, never content or ids. Sent from `CrudService.create()` / `update()` / `delete()` of a synchronized model (`CoreSyncService.notifyChange()` for a write past the CrudService), at most one per model and tenant per `hints.debounceMs`; received only by a subscriber with the model's pull roles and access to the tenant. With `redis` every replica's subscribers receive them (`<keyPrefix>:sync:hints`), without it only this replica's. A stream is registered like a WebSocket (`registerWsConnection()`) and ENDS on every invalidation or re-check, the client reconnects with its current rights. `hints: false` switches both channels off, `hints.sse` / `hints.graphql: false` one; no hint is a correctness signal — a missed one is caught by the next pull. **Tombstone purge**: tombstones older than `retention.tombstonesDays` (90; `false` keeps them for good, an invalid value → 90) are hard-deleted every hour on one replica (lease: Redis → the default SQL source's `lt_locks` → `cron-locks`), after the retention horizon moved past them — a client whose cursor predates the horizon answers `410 horizon`. `purgeTombstones()` runs it by hand. **Data migrations** of a synchronized table go through `runSqlMigration()` with `{ syncUpdate: { table, set, where } }`, which raises `version` and numbers the rows like a store write. **Client duties** (delete local data on logout and account switch, no token in `localStorage`, no cached API responses): `src/core/modules/sync/SECURITY.md`; reference test clients (PWA on IndexedDB, Node on SQLite) in `tests/clients/`. Overrides: `CoreModule.forRoot(env, { sync: { controller, hintsController, resolver, service } })` — the hints route is a controller of its own, registered before the pull route, because a project controller re-declaring `pull()` (`@Get(':model')`) would otherwise read `hints` as a model name. The purge deletes in batches of 1000 by id (one `DELETE … WHERE deleted_at < ?` locks every row it scans on MySQL / MariaDB). Implementation: `src/core/modules/sync/` (README, INTEGRATION-CHECKLIST), protocol `docs/offline-sync-protocol.md` |
329
330
  | BetterAuth Tenant Skip | `betterAuth.skipTenantCheck` | Explicit Boolean | `true` (default). When `true` and no `X-Tenant-Id` header is sent, IAM endpoints (controller + resolver) skip `CoreTenantGuard` tenant validation. When header IS present, normal membership validation runs regardless. Set `false` for tenant-aware auth scenarios (subdomain-based, invite links, SSO per tenant) |
330
331
  | Debug Process Input | `debugProcessInput` | Explicit Boolean | `false` (default). When `true`, logs a debug message when `prepareInput()` changes the input type during `process()`. Has performance cost due to `JSON.stringify` on every `process()` call — enable only for debugging |
@@ -345,7 +346,7 @@ This pattern is currently applied to:
345
346
  | Outbound URL Guard (SSRF) | `security.allowPrivateOutboundTargets` | Explicit Boolean with DERIVED default | **Opt-in helper for URLs a USER entered** (webhooks, export targets, ERP addresses) — `outboundFetch()`, `assertOutboundUrlAllowed()`, `createOutboundDispatcher()` in `common/helpers/outbound-url.helper.ts` (11.42.0). Nothing is applied globally: configured targets (AI providers, SMTP, S3, Redis, Brevo) never go through it. Refuses loopback, RFC 1918, link-local incl. `169.254.169.254`, CGNAT, `0/8`, benchmarking, multicast/reserved, IPv6 unspecified/loopback/IPv4-compatible (`::/96`), NAT64, ULA, link-local and multicast, and IPv4-mapped IPv6 in every notation (canonicalised through the URL parser). Checked TWICE: on the URL before sending (readable `OutboundUrlBlockedError`) and on every connection through an undici `Agent` with a guarded connector — the only place that sees a redirect's next hop and a DNS answer at connect time (rebinding). **Unset → derived from the environment**: allowed in `local`, `e2e`, `ci`, refused everywhere else — deliberately including `test`, a DEPLOYED stage in starter-based projects; `true`/`false` (also the strings, from `NSC__SECURITY__ALLOW_PRIVATE_OUTBOUND_TARGETS`) decide explicitly. Per call, `allowedHosts` frees single internal hosts (`'erp.local:8443'` = that port, `'erp.local'` = any port) without opening the rest — re-checked per connection, so a redirect does not inherit it. `outboundFetch()` uses undici's OWN `fetch` (runtime dependency `undici` since 11.42.0), because Node 22's built-in fetch bundles a different undici major than the agent |
346
347
  | AI Egress Allowlist (SSRF) | `ai.allowedBaseUrlHosts` | Explicit Value — **unset = permissive**, malformed = INTERPRETED or reported, never silently off | `undefined` → no restriction, so a local provider (Ollama on `localhost:11434`) works out of the box. Set → only those hosts are reachable, matched against `URL.host` (incl. port) and `URL.hostname`. **Accepts an array OR a comma-separated string, and the string form is not a convenience** — it is what the framework's own env mapping produces: `NSC__AI__ALLOWED_BASE_URL_HOSTS` becomes `{ ai: { allowedBaseUrlHosts: '<string>' } }` and lodash `merge` assigns that scalar straight over a configured array. Until 11.39.x a bare `!Array.isArray(...) -> return` read that as "not configured" and skipped the check entirely, so the canonical `NSC__` spelling silently disabled SSRF egress control with no log line at all. Entries are trimmed, lowercased and stripped of a fully-qualifying trailing dot, and the SAME normalisation is applied to the URL, so neither side wins by spelling one DNS name differently; a bare hostname entry matches any port, and an entry naming the scheme's default port (`example.com:443` on https) also matches the portless URL. A value that is neither array nor string carries no hostnames — the allowlist is then inactive and that is LOGGED as an error, because from the outside it looks exactly like "correctly unset". Enforced on **all three** outbound paths (`chat()`, the capability `probe()`, and `probeContextWindow()` — the last was unguarded before 11.39.x and is reachable from an ordinary user prompt via `detectAndPersistCapabilities()`, before the rate limit). Implementation: `openai-compatible.provider.ts` → `assertBaseUrlAllowed()` / `resolveAllowedBaseUrlHosts()` |
347
348
  | AI Run Time Limit | `ai.maxRunMs` | **Numeric Sentinel — Family A** (`0` = no limit) | `0` (omitted = unbounded, the previous behaviour). Wall-clock ceiling for ONE prompt run, checked before each agent-loop iteration; once exceeded the run stops and answers with whatever it has. **Without it a run's only bound is `maxIterations` MULTIPLIED BY the connection's per-call timeout** — 8 iterations at the 120s default is a request that can legitimately hold a socket, its message buffer and a request context for 16 minutes, and compaction can add a call per iteration on top. Guarded as `maxRunMs > 0`, never `<= 0`: a value arriving as a non-numeric string through `NSC__AI__MAX_RUN_MS` (the reader coerces only `'true'`, `'false'` and numbers) yields `NaN`, and `NaN > 0` is `false`, so a misconfiguration degrades to "no limit" rather than to an instantly-expired deadline that would break every prompt. Set it to something a client would actually wait for. Implementation: `core-ai.service.ts` -> `runDeadlineExceeded()` |
348
- | AI Assistant | `ai` | Presence Implies Enabled | Core: `maxIterations: 5`, `defaultMode: 'auto'` (or `'plan'`), `rateLimit` (presence implies enabled: `max: 20`, `windowSeconds: 60`), `systemPrompt`, `documentation` (injected into the system prompt), `encryptionSecret`. **DB-backed LLM connections** (`aiConnections`, admin CRUD) with AES-256-GCM-encrypted API keys (`AiCryptoService`, secret from `ai.encryptionSecret` / `NSC__AI__ENCRYPTION_SECRET` / `SECRETS_ENCRYPTION_KEY`; `apiKeyEncrypted` is a global `secretFields` entry, never returned — only `hasApiKey`); optional `defaultConnection` one-time seed. **Provider abstraction** (`ILlmProvider`, default `OpenAiCompatibleProvider` for any OpenAI-compatible endpoint via `fetch`; per-connection `supportsNativeTools`/`supportsJsonResponse` capabilities, emulated tool calling when native tools are unavailable). **Tool registry** (`AiToolRegistry`, tools self-register, role-filtered — under multi-tenancy (11.42.0+) a tool's roles resolve like `@Roles()` in `CoreTenantGuard`: global roles against `user.roles`, tenant roles against the request's membership role, ADMIN bypass only where `adminBypass` grants it, so chat and MCP never exceed the user's own rights; an MCP session reads the user per request, so a revoked role stops working without a reconnect; tools may be `mutating`/`destructive` and define `authorize()` for pre-flight data-level checks). **Plan mode** (`input.mode: 'plan'`): full plan → pre-flight authorize ALL steps → all-or-nothing execution with a translated (de/en) error when any step is not permitted. **Confirmation policy**: `confirmation.mutating: { default, enforced }` + client `input.requireConfirmation` (ignored when enforced); `destructive` always confirms. **Client metadata** (`input.metadata`: URL/nav/console logs, untrusted+capped). **Multi-turn conversations** (`aiConversations`, owner-scoped). **SSE streaming** (`POST /ai/stream`). **Audit** (`audit: false` → persist to `aiInteractions`, admin-readable). **Token budgets** (`budget: { period: 'day'|'month'|'none', user: { maxTokens?, maxPrompts? }, tenant: { maxTokens?, maxPrompts? } }`, requires audit): per-user AND per-tenant limits with config defaults; admins override per user/tenant at runtime (`aiBudgetLimits`, `CoreAiBudgetService`). Resolution: override → default → unlimited (missing/0 = unlimited). Enforced before the run (HTTP 429 + translated). Each response carries a compact `budget` summary (promptTokens, usedTokens, remainingTokens, resetAt); full breakdown via `aiUsage` query / `GET /ai/usage`. **Self-optimizing prompts**: the system prompt is assembled from keyed fragments (`CoreAiPromptBuilderService` ships built-in defaults; works with zero rows). Admin-editable overrides per slot (`aiSlots`, admin CRUD, `/ai/slots`) scoped by `key`/`locale`/`capability`/`tenantId`, with tenant override/reset semantics and placeholder tokens resolved at run time via the placeholder registry. **Governed learning loop** (`promptLearning: { enabled: true, autoApply: false }`): tool errors record `suggested` hints (`aiPromptHints`, admin CRUD, `/ai/prompt-hints`) that only reach the prompt once admin-approved (or auto-approved when `autoApply`); hints only ADD guidance, never relax permissions. **Context window** (`contextWindow`, default 8192; auto-detected per connection via `ILlmProvider.detectContextWindow()` — Ollama `/api/show` probe / known-model table / Claude alias — and persisted): per-user/session history is trimmed (oldest non-system turns dropped, last truncated) and tool-results capped to `maxToolResultChars` (default 12000) so a session never overflows the model. A connection's window can be seeded via `ai.defaultConnection.contextWindow` (validated: a non-positive/non-integer value is dropped with a warning). **Capability drift check** (`capabilityDriftCheck`, default `false`): opt-in boot self-check that probes each enabled connection with an EXPLICIT `supportsNativeTools`/`supportsJsonResponse` (built with those flags cleared so the endpoint is actually re-probed) and logs a warning on mismatch — the stored value is never changed. OFF by default because it makes outbound calls to the LLM endpoints on every boot; also skipped in the ci/e2e runners. **Deferred tool schemas** (`deferToolSchemas`, default `false`): the system-prompt tool catalog then lists only tool NAMES + descriptions instead of full JSON schemas, and the model fetches a schema on demand via the built-in `search_tools` meta-tool — with a large registry the schemas alone can dominate a small context window. `deferToolSummaryChars` (default `0` = untruncated) additionally caps each description in that DEFERRED catalog: whole sentences up to the cap (always at least the first), word-boundary cut when the first sentence already exceeds it, and a `…` marker appended ON TOP of the cap. The default of `0` keeps the saving opt-in, so enabling `deferToolSchemas` alone never changes what a description says; set roughly 200–400 alongside it to actually reclaim the context. Both apply to EMULATED providers only — a connection with `supportsNativeTools: true` receives every full description + schema via `buildToolSchemas()` regardless, so truncation and the banner are skipped there rather than asserting a cut the tool payload contradicts. The omitted tail is where preconditions and role restrictions usually live — the catalog banner tells the model to fetch the full text via `search_tools` first, but this is model GUIDANCE only: authorization is enforced server-side by the registry's role filter (`forUser()`), the execution-time re-check, and the `mutating`/`destructive` flags read by the confirmation gate — never by what the catalog shows. (`AiTool.authorize()` runs in PLAN MODE only; in auto mode and over MCP, data-level checks must live inside `execute()`.) **MCP server** (`mcp: false` → `/ai/mcp` Streamable HTTP, Bearer auth, lazy `@modelcontextprotocol/sdk`; `mcp: { oauth: true, oauthSecret }` adds OAuth 2.1 — HMAC tokens + PKCE S256 + dynamic registration. **Since 11.43.0 `CoreAiMcpOAuthInitializer` mounts the endpoints during `app.init()` (`onModuleInit`)** — behind the Nest middleware and routes, ahead of Nest's not-found handler; `mountAiMcpOAuth(app)` after `app.init()`, the documented way before, sat behind that handler and answered 404 everywhere, and is a no-op now. The protected resource is described at the path Nest registered `/ai/mcp` at (global prefix + exclusions, URI versioning, `RouterModule`, via Nest's own `RoutePathFactory`), and the MCP 401 names that metadata URL — plain `Bearer` without OAuth. Issuer: `mcp.oauthBaseUrl` (its origin is added to Better-Auth's `trustedOrigins`, explicit list included, via `withMcpOAuthIssuerOrigin()`), else `baseUrl`; a deployed environment with neither fails the boot. Signing secret required everywhere except `local` / `ci` / `e2e` (`allowsDevelopmentSecret()` → `isLocalEnv`), deployed `develop` / `test` stages included. Under a global prefix the consent page resolves the session itself (the Better-Auth middleware runs below the prefix only) and signs in at the prefixed IAM path. Express only (boot error otherwise); an application context without HTTP server mounts nothing. Consent: a built-in page (`authorizeConsent()` default) — sign-in through Better-Auth on the API origin (password + TOTP/backup code; passkey/social via `mcp.oauthLoginUrl`, default `<appUrl>/auth/login`), then Allow/Deny as a form POST with a CSRF token signed and bound to user, client, redirect URI and PKCE challenge (10 min); Allow is `disabled` until a nonce'd guard arms it and counts a click only after intent (visible + focused + pointer move / key / touch ≥ 600 ms later — against double-clickjacking); the account is shown first with "use another account"; own CSP with nonces + `frame-ancestors 'none'`, everything escaped; boot warning without Better-Auth; restyle via `renderConsentPage()`, replace via the `mcpOAuthService` override. A code saved while answering a GET to `/authorize` is refused for every consent implementation. Refusals are SDK `OAuthError` classes (`invalid_grant` etc.), never a plain `Error`, which the SDK answers as 500). Overrides via `CoreModule.forRoot(env, { ai: { budgetService, connectionResolver, connectionService, controller, conversationService, interactionService, mcpClientService, mcpOAuthService, modeService, placeholderRegistry, preferenceService, promptBuilder, promptHintService, promptService, resolver, service, slotService, toolGrantService, toolPolicyService } })` |
349
+ | AI Assistant | `ai` | Presence Implies Enabled | Core: `maxIterations: 5`, `defaultMode: 'auto'` (or `'plan'`), `rateLimit` (presence implies enabled: `max: 20`, `windowSeconds: 60`), `systemPrompt`, `documentation` (injected into the system prompt), `encryptionSecret`. **DB-backed LLM connections** (`aiConnections`, admin CRUD) with AES-256-GCM-encrypted API keys (`AiCryptoService`, secret from `ai.encryptionSecret` / `NSC__AI__ENCRYPTION_SECRET` / `SECRETS_ENCRYPTION_KEY`; `apiKeyEncrypted` is a global `secretFields` entry, never returned — only `hasApiKey`); optional `defaultConnection` one-time seed. **Provider abstraction** (`ILlmProvider`, default `OpenAiCompatibleProvider` for any OpenAI-compatible endpoint via `fetch`; per-connection `supportsNativeTools`/`supportsJsonResponse` capabilities, emulated tool calling when native tools are unavailable). **Tool registry** (`AiToolRegistry`, tools self-register, role-filtered — under multi-tenancy (11.42.0+) a tool's roles resolve like `@Roles()` in `CoreTenantGuard`: global roles against `user.roles`, tenant roles against the request's membership role, ADMIN bypass only where `adminBypass` grants it, so chat and MCP never exceed the user's own rights; an MCP session reads the user per request, so a revoked role stops working without a reconnect; tools may be `mutating`/`destructive` and define `authorize()` for pre-flight data-level checks). **Plan mode** (`input.mode: 'plan'`): full plan → pre-flight authorize ALL steps → all-or-nothing execution with a translated (de/en) error when any step is not permitted. **Confirmation policy**: `confirmation.mutating: { default, enforced }` + client `input.requireConfirmation` (ignored when enforced); `destructive` always confirms. **Client metadata** (`input.metadata`: URL/nav/console logs, untrusted+capped). **Multi-turn conversations** (`aiConversations`, owner-scoped). **SSE streaming** (`POST /ai/stream`). **Audit** (`audit: false` → persist to `aiInteractions`, admin-readable). **Token budgets** (`budget: { period: 'day'|'month'|'none', user: { maxTokens?, maxPrompts? }, tenant: { maxTokens?, maxPrompts? } }`, requires audit): per-user AND per-tenant limits with config defaults; admins override per user/tenant at runtime (`aiBudgetLimits`, `CoreAiBudgetService`). Resolution: override → default → unlimited (missing/0 = unlimited). Enforced before the run (HTTP 429 + translated). Each response carries a compact `budget` summary (promptTokens, usedTokens, remainingTokens, resetAt); full breakdown via `aiUsage` query / `GET /ai/usage`. **Self-optimizing prompts**: the system prompt is assembled from keyed fragments (`CoreAiPromptBuilderService` ships built-in defaults; works with zero rows). Admin-editable overrides per slot (`aiSlots`, admin CRUD, `/ai/slots`) scoped by `key`/`locale`/`capability`/`tenantId`, with tenant override/reset semantics and placeholder tokens resolved at run time via the placeholder registry. **Governed learning loop** (`promptLearning: { enabled: true, autoApply: false }`): tool errors record `suggested` hints (`aiPromptHints`, admin CRUD, `/ai/prompt-hints`) that only reach the prompt once admin-approved (or auto-approved when `autoApply`); hints only ADD guidance, never relax permissions. **Context window** (`contextWindow`, default 8192 — the fallback for connections without a window of their own; native tool definitions count against the input budget and a system prompt plus tools above half of it is warned about once per connection since 12.3.0; auto-detected per connection via `ILlmProvider.detectContextWindow()` — Ollama `/api/show` probe / known-model table / Claude alias — and persisted): per-user/session history is trimmed (oldest non-system turns dropped, last truncated) and tool-results capped to `maxToolResultChars` (default 12000) so a session never overflows the model. A connection's window can be seeded via `ai.defaultConnection.contextWindow` (validated: a non-positive/non-integer value is dropped with a warning). **Capability drift check** (`capabilityDriftCheck`, default `false`): opt-in boot self-check that probes each enabled connection with an EXPLICIT `supportsNativeTools`/`supportsJsonResponse` (built with those flags cleared so the endpoint is actually re-probed) and logs a warning on mismatch — the stored value is never changed. OFF by default because it makes outbound calls to the LLM endpoints on every boot; also skipped in the ci/e2e runners. **Deferred tool schemas** (`deferToolSchemas`, default `false`): the system-prompt tool catalog then lists only tool NAMES + descriptions instead of full JSON schemas, and the model fetches a schema on demand via the built-in `search_tools` meta-tool — with a large registry the schemas alone can dominate a small context window. `deferToolSummaryChars` (default `0` = untruncated) additionally caps each description in that DEFERRED catalog: whole sentences up to the cap (always at least the first), word-boundary cut when the first sentence already exceeds it, and a `…` marker appended ON TOP of the cap. The default of `0` keeps the saving opt-in, so enabling `deferToolSchemas` alone never changes what a description says; set roughly 200–400 alongside it to actually reclaim the context. Both apply to EMULATED providers only — a connection with `supportsNativeTools: true` receives every full description + schema via `buildToolSchemas()` regardless, so truncation and the banner are skipped there rather than asserting a cut the tool payload contradicts. **Native catalog** (`nativeToolCatalog`, 12.3.0+): such a connection's prompt catalog lists names only (`'names'`, default) instead of repeating what the payload carries; `'full'` restores it. Emulated connections and plan mode keep the full catalog. The omitted tail is where preconditions and role restrictions usually live — the catalog banner tells the model to fetch the full text via `search_tools` first, but this is model GUIDANCE only: authorization is enforced server-side by the registry's role filter (`forUser()`), the execution-time re-check, and the `mutating`/`destructive` flags read by the confirmation gate — never by what the catalog shows. (`AiTool.authorize()` runs before EVERY execution since 12.3.0 — auto mode, plan mode, MCP — on the arguments after the PreToolUse hooks, fail-closed; a refusal is `TOOL_NOT_AVAILABLE` with its reason and no learning signal, and `data` reaches `execute()` as `context.authorization.data`. Data access in `execute()` still goes through `CrudService` with `context.serviceOptions`.) **MCP server** (`mcp: false` → `/ai/mcp` Streamable HTTP, Bearer auth, lazy `@modelcontextprotocol/sdk`; since 12.3.0 `tools/call` applies the admin's tool policies (`deny` refuses, `ask` asks), `authorize()` and the confirmation of `destructive` tools (and `mutating` ones under `ai.confirmation.mutating`) through MCP elicitation — only an explicit yes runs the tool, a client without elicitation gets a refusal; `mcp.confirmation` (`true` default, `false`, `{ default, enforced }`, only `false` / `enforced: true` count) is the default each user may switch for themselves like a "bypass permissions" mode via `GET/PUT /ai/settings` / `aiSettings` / `updateAiSettings` (stored in `aiUserSettings`, 403 `#LTNS_0609` while enforced); `tools/list` annotates `destructive` / `mutating` tools (`destructiveHint`, `readOnlyHint: false`), an unflagged tool gets none — never advertised as read-only; `mcp.stateless: true` (12.3.0+, default `false`) serves `/ai/mcp` without sessions — a server and transport per POST, no `mcp-session-id`, a sent one ignored, GET / DELETE 405 with `Allow: POST`, auth and tenant per request — so any replica answers and no sticky sessions are needed; no server-initiated messages or requests there, so no elicitation: a tool that needs confirmation is refused unless the user or `mcp.confirmation` switched the question off; the consent page's wording and CSS change through `renderMcpOAuthConsentPage(view, { texts, styles })` from an overridden `renderConsentPage()` (code/config only; a `<` in styles is neutralized, CSP blocks external loads); `mcp: { oauth: true, oauthSecret }` adds OAuth 2.1 — HMAC tokens + PKCE S256 + dynamic registration. **Since 11.43.0 `CoreAiMcpOAuthInitializer` mounts the endpoints during `app.init()` (`onModuleInit`)** — behind the Nest middleware and routes, ahead of Nest's not-found handler; `mountAiMcpOAuth(app)` after `app.init()`, the documented way before, sat behind that handler and answered 404 everywhere, and is a no-op now. The protected resource is described at the path Nest registered `/ai/mcp` at (global prefix + exclusions, URI versioning, `RouterModule`, via Nest's own `RoutePathFactory`), and the MCP 401 names that metadata URL — plain `Bearer` without OAuth. Issuer: `mcp.oauthBaseUrl` (its origin is added to Better-Auth's `trustedOrigins`, explicit list included, via `withMcpOAuthIssuerOrigin()`), else `baseUrl`; a deployed environment with neither fails the boot. Signing secret required everywhere except `local` / `ci` / `e2e` (`allowsDevelopmentSecret()` → `isLocalEnv`), deployed `develop` / `test` stages included. Under a global prefix the consent page resolves the session itself (the Better-Auth middleware runs below the prefix only) and signs in at the prefixed IAM path. Express only (boot error otherwise); an application context without HTTP server mounts nothing. Consent: a built-in page (`authorizeConsent()` default) — sign-in through Better-Auth on the API origin (password + TOTP/backup code; passkey/social via `mcp.oauthLoginUrl`, default `<appUrl>/auth/login`), then Allow/Deny as a form POST with a CSRF token signed and bound to user, client, redirect URI and PKCE challenge (10 min); Allow is `disabled` until a nonce'd guard arms it and counts a click only after intent (visible + focused + pointer move / key / touch ≥ 600 ms later — against double-clickjacking); the account is shown first with "use another account"; own CSP with nonces + `frame-ancestors 'none'`, everything escaped; boot warning without Better-Auth; restyle via `renderConsentPage()`, replace via the `mcpOAuthService` override. A code saved while answering a GET to `/authorize` is refused for every consent implementation. Since 12.3.0 an error the SDK finds before the provider's `authorize` runs (a malformed request) is answered with 400 instead of a 302 to the client's self-registered redirect URI — that was an open redirect on the API domain (RFC 9700 §4.11.2); registration stays open (no redirect-URI allowlist, claude.ai / ChatGPT / Cursor / Claude Code register their own), and the built-in Deny needs the consent token like Allow (`mountAiMcpOAuthRouter()` wraps the SDK router, `authorizeConsent()`). Refusals are SDK `OAuthError` classes (`invalid_grant` etc.), never a plain `Error`, which the SDK answers as 500). Overrides via `CoreModule.forRoot(env, { ai: { budgetService, connectionResolver, connectionService, controller, conversationService, interactionService, mcpClientService, mcpOAuthService, modeService, placeholderRegistry, preferenceService, promptBuilder, promptHintService, promptService, resolver, service, slotService, toolGrantService, toolPolicyService, userSettingService } })` |
349
350
  | Swagger API-Token View | `setupSwagger(app, { apiTokenView })` (helper option, not server config) | Boolean Shorthand / Presence Implies Enabled | **Off without the option** (11.42.7+). `true` / `{}` serves a second document with only the routes that release a scope via `@ApiTokenScopes()`: UI at `swagger-api-tokens`, JSON at `/api-docs-api-tokens-json`, title `<title> — API tokens`, bearer as the only scheme, unused schemas pruned; the tenant header stays while `apiTokens.userTokens` is on (a personal token chooses the company like a session) and is dropped with company tokens only. Keep its path OUTSIDE the full UI's path: Swagger UI serves its assets below its own path. The full document's enrichment (global bearer + session-cookie requirement, `security: []` on public routes, `x-api-token-scopes` + description line, `TenantHeader` parameter) is not optional — it is what `setupSwagger()` is for, and it reads the same metadata as the guards. Implementation: `common/helpers/swagger.helper.ts` **Better-Auth routes (11.42.9):** the full document also lists every route Better-Auth serves itself under the base path — whatever the configured plugins add — from Better-Auth's own generator, under the project's Better-Auth controller (its tags and `operationTags`, ids `<Controller>_betterAuth_<id>`, schemas prefixed `BetterAuth`, OpenAPI 3.1 constructs converted to 3.0). Their security is what Better-Auth enforces, not the generator's blanket bearer-only: a route behind one of Better-Auth's session middlewares (or one of the three social-account routes in `HANDLER_SESSION_PATHS`, which check in the handler) gets the global requirement, every other route `security: []` — except routes of plugins nest-server does not register itself (`BUILT_IN_BETTER_AUTH_PLUGIN_IDS`), which always keep the global requirement — and if the instance's middlewares cannot be identified (two copies of better-auth), all of them keep the global requirement rather than risk documenting a session route as public. They carry the "not allowed" API-token line, and never reach the API-token view. The `openAPI()` plugin this needs is registered internally; its routes answer 404 (see `.claude/rules/better-auth.md` §9). **Only usable operations (11.42.9):** an operation that answers an error to every caller under the running configuration is left out — `@ApiMethods()` on `@All()` handlers (TUS), legacy `/auth/*` while `auth.legacyEndpoints` keeps REST closed, Better-Auth routes refused by the configuration or the live instance, Hub endpoints of switched-off panels. `/ai/mcp` and the MCP OAuth endpoints that are actually mounted are documented. An explicit `@ApiBearerAuth()` keeps a guard-public route from being documented as public. Rules: `isSwitchedOffOperation()` in `swagger.helper.ts` |
350
351
 
351
352
  ## Module Override Pattern (via `ICoreModuleOverrides`)
@@ -378,7 +379,7 @@ CoreModule.forRoot(CoreAuthService, AuthModule.forRoot(envConfig.jwt), envConfig
378
379
 
379
380
  | Module | Fields | Description |
380
381
  |--------|--------|-------------|
381
- | `ai` | `budgetService`, `connectionResolver`, `connectionService`, `controller`, `conversationService`, `interactionService`, `mcpClientService`, `mcpOAuthService`, `modeService`, `placeholderRegistry`, `preferenceService`, `promptBuilder`, `promptHintService`, `promptService`, `resolver`, `service`, `slotService`, `toolGrantService`, `toolPolicyService` | Custom AI orchestrator, connection-resolution chain, connection/preference/budget/conversation/interaction/MCP-client services, MCP OAuth service (the consent step), slot + user-prompt + learning-hint stores, mode service, placeholder registry, tool-grant + tool-policy services, endpoints |
382
+ | `ai` | `budgetService`, `connectionResolver`, `connectionService`, `controller`, `conversationService`, `interactionService`, `mcpClientService`, `mcpOAuthService`, `modeService`, `placeholderRegistry`, `preferenceService`, `promptBuilder`, `promptHintService`, `promptService`, `resolver`, `service`, `slotService`, `toolGrantService`, `toolPolicyService`, `userSettingService` | Custom AI orchestrator, connection-resolution chain, connection/preference/budget/conversation/interaction/MCP-client services, MCP OAuth service (the consent step), slot + user-prompt + learning-hint stores, mode service, placeholder registry, tool-grant + tool-policy services, personal-settings store, endpoints |
382
383
  | `errorCode` | `controller`, `service` | Custom error code endpoint and/or service |
383
384
  | `betterAuth` | `controller`, `resolver` | Custom IAM REST controller and/or GraphQL resolver |
384
385
  | `hub` | `controller`, `actionsController`, `service`, `htmlService`, `actionsService` | Custom Hub page/actions controllers and aggregator/HTML/actions services (each must extend its `Core*` base) |
@@ -370,7 +370,7 @@ removed an export its consumer imports, or the consumer pins the vulnerable rang
370
370
  `FIX AVAILABLE` is not advice but a dead end, and the only ways out used to be a permanently red
371
371
  build or a guard switched off for that entry.
372
372
 
373
- Measured case (lt-crm, 2026-10-06): three `simple-git` advisories, one CRITICAL requiring `>=4.0.1`,
373
+ Measured case (a consuming Nuxt project, 2026-10-06): three `simple-git` advisories, one CRITICAL requiring `>=4.0.1`,
374
374
  reachable only via `nuxt > @nuxt/devtools > simple-git`. simple-git 4 dropped the default export
375
375
  devtools imports, so the override made `nuxt prepare` fail outright. The newest devtools in the 3.x
376
376
  line still imports it that way, and devtools is a hard `dependencies` entry of `nuxt` — so it can be
@@ -401,6 +401,18 @@ any has moved:
401
401
  second version of the same consumer is a path nobody assessed, and comparing by name alone let
402
402
  one ride along on the other's declaration, with the winner decided by lockfile order.
403
403
 
404
+ **"Pulls an affected package" means an affected VERSION (12.3.0).** Checks 3 and the idle check below
405
+ count an edge only when its resolved version lies in one of the advisory's `vulnerable_version_range`s.
406
+ A parent pulling the FIXED release is no consumer of the vulnerability. Until 12.3.0 every parent
407
+ counted, so lifting one subtree to the fixed major (glob 14.0.3 pulling minimatch 11.0.3 next to
408
+ consumers still on minimatch 10) failed a correct declaration for good. An edge whose version cannot be
409
+ read (`link:`, `file:`), or any edge of an advisory that lists no range, still counts: "I could not tell
410
+ which version it pulls" must not read as "it pulls the fixed one" (mutations
411
+ `unusable-fix-counts-fixed-edges`, `unusable-fix-skips-unreadable-edge`). An edge is matched by the package it
412
+ PULLS, not by its key: pnpm keys an npm alias by the alias (`mm-cjs: minimatch@5.1.9`, an importer's
413
+ `version: minimatch@5.1.9`), so a key match missed every consumer behind an alias and read an edge keyed
414
+ `minimatch` that pulls a fork as a minimatch edge (mutation `unusable-fix-matches-alias-by-key`).
415
+
404
416
  **Several consumers (12.1.1+)** are joined with ` + `, each at its assessed version —
405
417
  `'@nestjs/cli@12.0.11 + nodemon@3.1.14 cannot use 11.0.1'`. One vulnerable package often sits under
406
418
  several dev tools at once, and before this a declaration could name only one, so such a finding had no
@@ -1,7 +1,7 @@
1
1
  # Persistence Rules (MongoDB, PostgreSQL, MySQL and MariaDB)
2
2
 
3
3
  These rules apply to every model, service and query — in `src/core/` and in projects. The design and its
4
- reasoning are in `.claude/plans/db-agnostic/PLAN.md` (framework repository); which database a project uses is decided by
4
+ reasoning are in the db-agnostic design plan (internal, not part of this repository); which database a project uses is decided by
5
5
  `docs/choosing-a-database.md`; the configuration reference is the "Data Sources" row of
6
6
  `.claude/rules/configurable-features.md`.
7
7
 
@@ -94,7 +94,7 @@ whole process. Never build an update path from request data without validating i
94
94
  ## Synchronized models (offline sync, 12.x)
95
95
 
96
96
  `@PersistedModel({ sync: true | { idFormat, scope } })` makes a model synchronizable (`common/persistence/sync-model.ts`,
97
- plan `.claude/plans/offline-sync/PLAN.md` §3.3). Only a model registered with `CorePersistenceModule.forFeature()`; a
97
+ offline-sync plan §3.3). Only a model registered with `CorePersistenceModule.forFeature()`; a
98
98
  model without `sync` keeps every behaviour bit for bit.
99
99
 
100
100
  | Rule | Why |
@@ -82,7 +82,7 @@ pnpm run test:infra:down # stop and remove
82
82
  | Port | 6380 (6379 is an auth-protected TurboOps Redis on lt dev machines) | 9102 | 5440 | 3316 | 3317 | 27019 |
83
83
  | Container | `nest-server-2985-redis` | `nest-server-2985-rustfs` | `nest-server-2985-postgres` | `nest-server-2985-mysql` | `nest-server-2985-mariadb` | `nest-server-2985-mongo-rs` |
84
84
 
85
- **PostgreSQL runs with two roles, as every environment does** (`.claude/plans/db-agnostic/PLAN.md`
85
+ **PostgreSQL runs with two roles, as every environment does** (db-agnostic plan
86
86
  §3.9): `nest_owner` owns the databases and their schema, `nest_app` owns nothing and has neither
87
87
  superuser nor `BYPASSRLS` — so a suite running as the application role meets row-level security the
88
88
  way production does. The readiness step creates `nest_app`, which is why the container is started
@@ -410,7 +410,7 @@ pnpm run check:mutations -- --id=<id> # one mutation
410
410
  pnpm run check:mutations -- --list # the registry, without running anything
411
411
  pnpm run check:mutations -- --allow-dirty # when the fix and its evidence share a working tree
412
412
  pnpm run check:mutations -- --jobs=4 # N mutations at a time (default: 2, or 4 on >=12 cores)
413
- pnpm run check:mutations -- --no-infra # only the 260 that need no MongoDB
413
+ pnpm run check:mutations -- --no-infra # only the 311 that need no MongoDB
414
414
  pnpm run check:mutations -- --since=<ref> # only mutations touching files changed since <ref>
415
415
  pnpm run check:mutations -- --shard=2/4 # this job's quarter of the selection (CI splits the full run)
416
416
  ```
@@ -430,7 +430,7 @@ when the registry, a vitest config or a setup file changed, since those can move
430
430
  commit, and in CI alongside the publish without blocking it. The price of caching is a cache that
431
431
  has to model each spec's full dependency closure correctly, and getting that wrong produces a stale
432
432
  PASS for a test that has since gone vacuous — exactly what the gate is there to prevent. Bad trade
433
- at 476 mutations.
433
+ at 530 mutations.
434
434
 
435
435
  **Decided 2026-10-03 (repo owner): keep the full run.** Measured at 128 mutations, the CI job for
436
436
  11.41.6 took **14 minutes**. The trigger to revisit is that wall time, not the mutation count —
@@ -501,9 +501,9 @@ exactly the environment where the answer matters.
501
501
 
502
502
  ### The cost is vitest's cold start, not the tests
503
503
 
504
- Worth knowing before optimising the wrong thing: the specs behind all 216 e2e mutations add up to
504
+ Worth knowing before optimising the wrong thing: the specs behind all 219 e2e mutations add up to
505
505
  **~40 seconds**. The step takes ~740s. The remaining ~700s is paying vitest's startup — process
506
- spawn, transform, module graph, mongod connect, DB create and drop — once per mutation, 476 times.
506
+ spawn, transform, module graph, mongod connect, DB create and drop — once per mutation, 530 times.
507
507
  That work is largely single-threaded I/O and barely scales with cores: the full registry measures
508
508
  **744s on a 12-core laptop and 777s on a 4-vCPU CI runner**.
509
509
 
@@ -25,6 +25,13 @@
25
25
  1. **Document breaking changes** clearly in commit messages when incrementing MINOR version
26
26
  2. **Update nest-server-starter** with migration instructions for breaking changes
27
27
  3. **Consider downstream impact** - this package is used by multiple projects
28
+ 4. **Every published version gets its nest-server-starter version** (repo owner, 2026-11-03). The
29
+ starter's `version` always equals the `@lenne.tech/nest-server` version it pins. Every version
30
+ published to npm is followed by the starter commit `Updated to nest-server version <X.Y.Z>`, tagged
31
+ `v<X.Y.Z>` by the starter's `tag.yml`, also when the bump is the only change. Starter changes
32
+ between two releases never change its version: the starter follows nest-server, never the other
33
+ way round. This covers the maintenance line too: a release from `release/11.x` is followed on the
34
+ starter's `release/11.x` branch.
28
35
 
29
36
  ## Release Process
30
37
 
@@ -36,8 +43,12 @@
36
43
  (You can also sync manually any time via `pnpm run spectaql:sync`.)
37
44
  3. Build the package (`pnpm run build`) — this also regenerates `FRAMEWORK-API.md` with the new version
38
45
  4. Publish to npm
39
- 5. Update and test in [nest-server-starter](https://github.com/lenneTech/nest-server-starter)
40
- 6. Commit changes to starter with migration notes
46
+ 5. **Release [nest-server-starter](https://github.com/lenneTech/nest-server-starter) with the same
47
+ version — a required step, not an optional "update and test".** Raise the framework and the
48
+ starter's own `version` to the new version (`pnpm run update`, migration guides applied), test, and
49
+ commit as `Updated to nest-server version <X.Y.Z>`; the starter's `tag.yml` tags it `v<X.Y.Z>` (rule 4).
50
+ 6. A release made with `/lt-dev:publish --skip-downstream` leaves a gap in the starter's tag series.
51
+ Close it before the next nest-server release.
41
52
 
42
53
  ### Version Consistency Check
43
54
 
package/CLAUDE.md CHANGED
@@ -192,6 +192,11 @@ pnpm run reinit # Clean reinstall + tests + build
192
192
 
193
193
  ## Code Architecture
194
194
 
195
+ **Internal notes are not in this repository.** The review agents' memory (`.claude/agent-memory`) and the design
196
+ plans of larger epics (`.claude/plans`, cited in code comments as `plan §3.4` or `offline-sync plan §3.4`) live in a
197
+ private repository of the team and are linked in as gitignored symlinks. This repository is public: never copy their
198
+ contents into a tracked file, a commit message or a PR. Pinned by `tests/unit/public-repo-hygiene.spec.ts`.
199
+
195
200
  **Two-Layer Structure:**
196
201
  - `src/core/` - Reusable framework components (exported)
197
202
  - `src/server/` - Internal test implementation (not exported)
package/FRAMEWORK-API.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @lenne.tech/nest-server — Framework API Reference
2
2
 
3
- > Auto-generated from source code as of 2026-11-01 (v12.2.0)
3
+ > Auto-generated from source code as of 2026-11-03 (v12.3.0)
4
4
  > File: `FRAMEWORK-API.md` — compact, machine-readable API surface for Claude Code
5
5
 
6
6
  ## CoreModule.forRoot()
@@ -129,11 +129,12 @@ When `passkey` is enabled, `trustedOrigins` is required (compile-time enforcemen
129
129
  - `compaction?`: `boolean` (default: `true`) — LLM-driven context compaction: when a session would overflow the connection's
130
130
  - `deferToolSchemas?`: `boolean` (default: `false`) — Defer the parameter schemas of tools out of the system prompt. With many tools
131
131
  - `deferToolSummaryChars?`: `number` (default: `0`) — Maximum characters per tool description in the DEFERRED catalog
132
+ - `nativeToolCatalog?`: `"full" | "names"` (default: `'names'`) — What the system prompt's tool catalog holds for a connection with NATIVE tool calling in auto mode (12.3.0+).
132
133
  - `maxIterations?`: `number` (default: `5`) — Maximum number of agent-loop iterations (tool round-trips).
133
134
  - `maxRunMs?`: `number` (default: `0`) — Wall-clock ceiling for ONE prompt run, in milliseconds. Checked before each
134
135
  - `maxToolResultChars?`: `number` (default: `12000`) — Maximum characters of a tool-results payload fed back to the model.
135
136
  - `promptLearning?`: `{ autoApply?: boolean; enabled?: boolean; minOccurrences?: number; }` — Governed self-improvement loop for the system prompt. The orchestrator records
136
- - `mcp?`: `boolean | { enabled?: boolean; oauth?: boolean; oauthBaseUrl?: string; oauthL...` (default: `false`) — Expose the tool registry as an MCP server at `/ai/mcp` (Streamable HTTP) for
137
+ - `mcp?`: `boolean | { confirmation?: boolean | { default?: boolean; enforced?: boolean;...` (default: `false`) — Expose the tool registry as an MCP server at `/ai/mcp` (Streamable HTTP) for
137
138
  - `rateLimit?`: `IAiRateLimit` — Rate limiting for prompts.
138
139
  - `systemPrompt?`: `string` — Base system prompt prepended to every conversation.
139
140
 
@@ -247,7 +248,7 @@ When `passkey` is enabled, `trustedOrigins` is required (compile-time enforcemen
247
248
 
248
249
  ### IBetterAuthEmailVerificationConfig
249
250
 
250
- - `autoSignInAfterVerification?`: `boolean` (default: `true`) — Whether to automatically sign in the user after email verification.
251
+ - `autoSignInAfterVerification?`: `boolean` (default: `false`) — Whether `GET /iam/verify-email` signs in the browser that opens the verification link.
251
252
  - `brevoTemplateId?`: `number` (default: `undefined (uses SMTP/EJS templates)`) — Brevo template ID for verification emails.
252
253
  - `callbackURL?`: `string` (default: `undefined (backend-handled verification)`) — Frontend callback URL for email verification.
253
254
  - `enabled?`: `boolean` (default: `true (enabled by default when BetterAuth is active)`) — Whether email verification is enabled.
package/README.md CHANGED
@@ -383,9 +383,9 @@ Details: [src/core/modules/sync/README.md](src/core/modules/sync/README.md), cli
383
383
  An optional AI module (`ai` configuration) for any OpenAI-compatible model endpoint:
384
384
 
385
385
  - **Tool registry** — the assistant reaches exactly the domain operations a project registers as tools, filtered by the user's roles; a tool must route through a `CrudService` with the caller's service options, so that `@Restricted` and `securityCheck()` apply
386
- - **Plan mode and confirmations** — a full plan is authorized step by step before anything runs; in chat, destructive tools always ask for confirmation, mutating tools only under `ai.confirmation.mutating` (off by default, can be enforced)
386
+ - **Authorization and confirmations** — a tool's `authorize()` checks every call before it runs (auto mode, plan mode, MCP), and plan mode authorizes the whole plan before anything runs; destructive tools ask for confirmation, mutating tools only under `ai.confirmation.mutating` (off by default, can be enforced)
387
387
  - **Token budgets** per user and per tenant, conversations, audit log, SSE streaming, admin-editable prompt fragments
388
- - **MCP server** at `/ai/mcp` (Streamable HTTP) with optional OAuth 2.1 (PKCE, dynamic client registration, consent page), so MCP clients use the same tools with the same rights; there is no confirmation gate over MCP, the client's own approval applies
388
+ - **MCP server** at `/ai/mcp` (Streamable HTTP) with optional OAuth 2.1 (PKCE, dynamic client registration, consent page), so MCP clients use the same tools with the same rights; `tools/call` applies the admin's tool policies and `authorize()`, and asks the user through MCP elicitation before a destructive tool (`ai.mcp.confirmation`, on by default; each user may switch it off for themselves via `PUT /ai/settings` unless the server enforces it)
389
389
 
390
390
  Integration: [src/core/modules/ai/INTEGRATION-CHECKLIST.md](src/core/modules/ai/INTEGRATION-CHECKLIST.md).
391
391
 
@@ -25,7 +25,7 @@ const config = {
25
25
  rpId: 'localhost',
26
26
  rpName: 'Nest Server Local',
27
27
  },
28
- rateLimit: { enabled: true, max: 100, windowSeconds: 60 },
28
+ rateLimit: { enabled: true, max: 200, windowSeconds: 60 },
29
29
  secret: process.env.BETTER_AUTH_SECRET || 'BETTER_AUTH_SECRET_LOCAL_32_CHARS_M',
30
30
  socialProviders: {
31
31
  apple: { clientId: '', clientSecret: '', enabled: false },
@@ -274,7 +274,7 @@ const config = {
274
274
  rpId: 'localhost',
275
275
  rpName: 'Nest Server Local',
276
276
  },
277
- rateLimit: { enabled: true, max: 100, windowSeconds: 60 },
277
+ rateLimit: { enabled: true, max: 200, windowSeconds: 60 },
278
278
  secret: process.env.BETTER_AUTH_SECRET || 'BETTER_AUTH_SECRET_LOCAL_32_CHARS_M',
279
279
  socialProviders: {
280
280
  apple: { clientId: '', clientSecret: '', enabled: false },
@@ -1 +1 @@
1
- {"version":3,"file":"config.env.js","sourceRoot":"","sources":["../src/config.env.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.env.js","sourceRoot":"","sources":["../src/config.env.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,8 @@ export interface IWsConnectionSocket {
9
9
  }
10
10
  export interface IWsConnectionRegistration {
11
11
  carrier: object;
12
+ channel?: string;
13
+ endsOnRecheck?: boolean;
12
14
  reauthenticate?: () => any;
13
15
  socket?: IWsConnectionSocket;
14
16
  user: any;
@@ -19,7 +21,9 @@ export interface IWsConnectionIdentity {
19
21
  userId?: string;
20
22
  }
21
23
  export interface WsConnection {
24
+ readonly channel: string;
22
25
  readonly email?: string;
26
+ readonly endsOnRecheck: boolean;
23
27
  readonly iamId?: string;
24
28
  readonly reauthenticate?: () => any;
25
29
  readonly socket?: IWsConnectionSocket;