@lenne.tech/nest-server 11.42.5 → 11.42.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/rules/configurable-features.md +2 -1
- package/.claude/rules/testing.md +3 -3
- package/FRAMEWORK-API.md +1 -1
- package/dist/core/common/helpers/swagger.helper.d.ts +11 -0
- package/dist/core/common/helpers/swagger.helper.js +362 -0
- package/dist/core/common/helpers/swagger.helper.js.map +1 -0
- package/dist/core/common/interfaces/swagger-setup-options.interface.d.ts +33 -0
- package/dist/core/common/interfaces/swagger-setup-options.interface.js +3 -0
- package/dist/core/common/interfaces/swagger-setup-options.interface.js.map +1 -0
- package/dist/core/common/services/core-body-parser.initializer.d.ts +2 -0
- package/dist/core/common/services/core-body-parser.initializer.js +23 -3
- package/dist/core/common/services/core-body-parser.initializer.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/main.js +8 -14
- package/dist/main.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/docs/REQUEST-LIFECYCLE.md +1 -1
- package/migration-guides/11.42.3-to-11.42.4.md +10 -1
- package/migration-guides/11.42.5-to-11.42.6.md +113 -0
- package/migration-guides/11.42.6-to-11.42.7.md +115 -0
- package/package.json +4 -4
- package/src/core/common/helpers/swagger.helper.ts +529 -0
- package/src/core/common/interfaces/server-options.interface.ts +5 -0
- package/src/core/common/interfaces/swagger-setup-options.interface.ts +131 -0
- package/src/core/common/services/core-body-parser.initializer.ts +47 -5
- package/src/index.ts +2 -0
- package/src/main.ts +9 -15
|
@@ -335,12 +335,13 @@ This pattern is currently applied to:
|
|
|
335
335
|
| TUS S3 Staging | `tus.s3Staging` | Explicit Boolean (default ON when S3 configured) | `true` when `s3` is configured, otherwise inert. Stages in-progress uploads in `s3.stagingBucket` via `@tus/s3-store` instead of `tus.uploadDir` on local disk, so resumable uploads survive replica restarts and need no sticky sessions. Set `false` to force local disk. Missing OPTIONAL peer `@tus/s3-store` → warning + fall back to local disk (NOT a boot failure). **Give the staging bucket a lifecycle rule expiring incomplete multipart uploads** — the framework's own expiration cleanup is skipped in S3 mode (S3 is the right place for that policy), so aborted uploads otherwise accumulate parts nothing removes |
|
|
336
336
|
| Cron Job Deduplication | per job: `distributed` in `CronJobConfig` | Explicit Boolean | **`true` when `redis` is configured, otherwise `false`** — a single-replica project that upgrades must not silently gain a `cron-locks` collection, a lease write per tick, and a new way for a tick to be skipped. A Redis-less multi-replica fleet opts in per job with `distributed: true` (MongoDB lease). Mechanism: BullMQ job scheduler when Redis + the OPTIONAL peer `bullmq` are present AND `cronTime` is a string without `utcOffset`; otherwise local timer + lease (Redis `SET NX`, else a TTL-indexed `cron-locks` document). Tick lease TTL 3600 s. **Leases fail open** — an unreachable lease store runs the tick everywhere rather than stopping all scheduled work fleet-wide. **`runOnInit` (default `true`) deduplicates over a FIXED per-job key with a 300 s TTL**, because replicas do not share a boot instant: replicas booting within 5 min run the startup tick once between them, and a replica restarting inside that window SKIPS its startup tick — set `distributed: false` on jobs whose `runOnInit` work is per-process (warming a process-local cache). No constructor change needed: `CoreModule` fills `core-cron-jobs.registry.ts` via `CoreCronJobsInitializer` and `CoreCronJobs` reads it lazily; explicit `{ connection, redisService }` in `CoreCronJobsOptions` wins. With neither source it warns once and every replica runs every tick |
|
|
337
337
|
| Shutdown Delay | `shutdownDelayMs` | Numeric Sentinel — Family B (`0` = off) | `0` (default, no delay, no log). Waits N ms **in the SIGTERM/SIGINT handler, before `close()` is entered**, so a load balancer can finish deregistering while the instance is still fully healthy. NOT a lifecycle hook: `close()` runs `onModuleDestroy` → `beforeApplicationShutdown` → dispose → `onApplicationShutdown`, so a delay in `beforeApplicationShutdown` would wait with every module already torn down while the socket still accepts — worse than no delay. **Requires `installGracefulShutdown(app)` in main.ts, which REPLACES `server.enableShutdownHooks()`** — keeping both makes Nest close the app in parallel with the wait, so the delay silently never happens. At delay `0` the helper IS `enableShutdownHooks()`. **Keep the value well below the orchestrator grace period AND leave room for the drain that follows**: Compose `stop_grace_period` 10s, Kubernetes `terminationGracePeriodSeconds` 30s, and `installProcessDiagnostics()` force-exits after 30s — exceed any and the process is SIGKILLed mid-wait with no hook running. Warns above `10000`, capped at `60000`. Non-numeric / negative values behave like `0` |
|
|
338
|
-
| Body Parser Limits | `bodyParser.json.limit`, `bodyParser.urlencoded.limit` | Explicit Value (Express/body-parser default) — invalid → default, never unbounded | **Unset = 100 kB each, exactly as NestJS registers the parsers** (body-parser's own default — a limit nobody chose, and before 11.42.4 the only one in force: over it a request got a bare `request entity too large`, before auth and routing, GraphQL included). A number is bytes, a string a 1024-based size (`'500kb'`, `'2mb'`, units `b`/`kb`/`mb`/`gb`). The two limits are separate on purpose — raising JSON must not raise form posts. **Not raised by default because the parser runs before authentication** and `JSON.parse` blocks the event loop for the whole body: ~0.5 ms for 100 kB, ~16 ms for 1 MB, ~55 ms for 2 MB per request on a realistic document shape. Applied by `CoreBodyParserInitializer` (CoreModule provider) in `onModuleInit` by **swapping the handle of the global `jsonParser`/`urlencodedParser` layers NestJS registered, in place** — NestJS registers them inside `app.init()` before any init hook, and a parser appended later would sit behind the routes. Same position, `extended: true` for URL-encoded, `req.rawBody` kept when the app came from `NestFactory.create(…, { rawBody: true })` (read from the container's context options; under `Test.createTestingModule()` those options never reach the container, so a test app with `rawBody: true` gets no `req.rawBody` from a CONFIGURED parser). Because it runs during module init it **holds under `Test.createTestingModule()`**, which never runs `main.ts` — the reason a `useBodyParser()` in `main.ts` was not enough. A configured value also replaces a global parser registered in `main.ts`; a **path-scoped** one (`server.use('/upload', json({ limit }))`) is left alone and stays the way to give one path its own limit (the parser runs before routing; GraphQL shares one path). An invalid value (`0`, negative, `NaN`, a word) is refused with an error log and the parser keeps its limit. **Independent of configuration**, every 413 from a global parser is answered as `PayloadTooLargeException` with `#LTNS_0304: Request body too large [<n> bytes, limit <m> bytes]` (size only when a `Content-Length` was sent) and logged as a WARN naming method, path without query string, and the config key — no boot warning, because the framework cannot know which routes expect large bodies; the first oversized request is the earliest point anything can be said. Other parser errors pass through unchanged. Pinned by `tests/unit/body-parser.spec.ts` and `tests/body-parser.e2e-spec.ts` (mutations `body-parser-*`). Implementation: `common/services/core-body-parser.initializer.ts` |
|
|
338
|
+
| Body Parser Limits | `bodyParser.json.limit`, `bodyParser.urlencoded.limit` | Explicit Value (Express/body-parser default) — invalid → default, never unbounded | **Unset = 100 kB each, exactly as NestJS registers the parsers** (body-parser's own default — a limit nobody chose, and before 11.42.4 the only one in force: over it a request got a bare `request entity too large`, before auth and routing, GraphQL included). A number is bytes, a string a 1024-based size (`'500kb'`, `'2mb'`, units `b`/`kb`/`mb`/`gb`). The two limits are separate on purpose — raising JSON must not raise form posts. **Not raised by default because the parser runs before authentication** and `JSON.parse` blocks the event loop for the whole body: ~0.5 ms for 100 kB, ~16 ms for 1 MB, ~55 ms for 2 MB per request on a realistic document shape. Applied by `CoreBodyParserInitializer` (CoreModule provider) in `onModuleInit` by **swapping the handle of the global `jsonParser`/`urlencodedParser` layers NestJS registered, in place** — NestJS registers them inside `app.init()` before any init hook, and a parser appended later would sit behind the routes. Same position, `extended: true` for URL-encoded, `req.rawBody` kept when the app came from `NestFactory.create(…, { rawBody: true })` (read from the container's context options; under `Test.createTestingModule()` those options never reach the container, so a test app with `rawBody: true` gets no `req.rawBody` from a CONFIGURED parser). Because it runs during module init it **holds under `Test.createTestingModule()`**, which never runs `main.ts` — the reason a `useBodyParser()` in `main.ts` was not enough. A configured value also replaces a global parser registered in `main.ts`; a **path-scoped** one (`server.use('/upload', json({ limit }))`) is left alone and stays the way to give one path its own limit (the parser runs before routing; GraphQL shares one path). **Keep `server.useBodyParser('json')` in `main.ts` next to a path-scoped parser**: NestJS registers its global parser only when no layer with the same FUNCTION NAME exists (`isMiddlewareApplied()`), so a path-scoped `json()` registered before `app.init()` suppresses it and every other path gets an empty body (a sign-in fails with a validation error). Since 11.42.6 the initializer warns at boot about exactly that (`warnMissingGlobalParser()`). It deliberately does not re-insert the parser: NestJS would have placed it after everything `main.ts` registered, a position no longer knowable during module init, and a raw-body webhook or proxy registered after the path-scoped parser must keep seeing the unread stream. An invalid value (`0`, negative, `NaN`, a word) is refused with an error log and the parser keeps its limit. **Independent of configuration**, every 413 from a global parser is answered as `PayloadTooLargeException` with `#LTNS_0304: Request body too large [<n> bytes, limit <m> bytes]` (size only when a `Content-Length` was sent) and logged as a WARN naming method, path without query string, and the config key — no boot warning, because the framework cannot know which routes expect large bodies; the first oversized request is the earliest point anything can be said. Other parser errors pass through unchanged. Pinned by `tests/unit/body-parser.spec.ts` and `tests/body-parser.e2e-spec.ts` (mutations `body-parser-*`). Implementation: `common/services/core-body-parser.initializer.ts` |
|
|
339
339
|
| Trust Proxy | `trustProxy` | Explicit Value (pass-through, Express default) | `false` (Express's own default — the forwarded chain is not trusted). Passed verbatim to `app.set('trust proxy', …)` by `CoreTrustProxyInitializer`, a `CoreModule` provider, so a consumer inherits it by upgrading and needs no `main.ts` edit. Accepts `false` / a hop count (`1`, `2`) / `'loopback'` / a subnet list — **not** Express's predicate function: the value must survive `NEST_SERVER_CONFIG` / `NSC__*` (JSON) and the ConfigService deep clone. **This is what makes `request.ip` correct, and every IP-keyed rate limit depends on it**: unset behind Caddy/nginx/an ingress, `req.ip` is the PROXY address for every request, so all clients share ONE bucket and `auth.rateLimit.max` throttles everybody at once — exactly fleet-wide once `redis` is configured. Trusting MORE hops than exist is the opposite failure: a client prepends its own header entry and picks a fresh bucket per request. Applied at module init (inside `app.init()`/`listen()`, i.e. AFTER `main.ts`), so a configured value wins over a hand-written `app.set()`; an UNSET value is never applied, which keeps `app.set('trust proxy', fn)` in `main.ts` available as the escape hatch for the predicate form. **Unset + an IP-keyed limiter enabled (`auth.rateLimit` / `betterAuth.rateLimit`) logs a boot warning naming the shared-bucket consequence**; `trustProxy: false` is the explicit "nothing proxies me" answer that silences it. The AI limiter keys on the user id and is unaffected |
|
|
340
340
|
| 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 |
|
|
341
341
|
| 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()` |
|
|
342
342
|
| 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()` |
|
|
343
343
|
| 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 via `mountAiMcpOAuth(app)` in main.ts). Overrides via `CoreModule.forRoot(env, { ai: { budgetService, connectionResolver, connectionService, controller, conversationService, interactionService, mcpClientService, modeService, placeholderRegistry, preferenceService, promptBuilder, promptHintService, promptService, resolver, service, slotService, toolGrantService, toolPolicyService } })` |
|
|
344
|
+
| 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` |
|
|
344
345
|
|
|
345
346
|
## Module Override Pattern (via `ICoreModuleOverrides`)
|
|
346
347
|
|
package/.claude/rules/testing.md
CHANGED
|
@@ -266,7 +266,7 @@ pnpm run check:mutations -- --id=<id> # one mutation
|
|
|
266
266
|
pnpm run check:mutations -- --list # the registry, without running anything
|
|
267
267
|
pnpm run check:mutations -- --allow-dirty # when the fix and its evidence share a working tree
|
|
268
268
|
pnpm run check:mutations -- --jobs=4 # N mutations at a time (default: 2, or 4 on >=12 cores)
|
|
269
|
-
pnpm run check:mutations -- --no-infra # only the
|
|
269
|
+
pnpm run check:mutations -- --no-infra # only the 109 that need no MongoDB
|
|
270
270
|
pnpm run check:mutations -- --since=<ref> # only mutations touching files changed since <ref>
|
|
271
271
|
```
|
|
272
272
|
|
|
@@ -285,7 +285,7 @@ when the registry, a vitest config or a setup file changed, since those can move
|
|
|
285
285
|
commit, and in CI alongside the publish without blocking it. The price of caching is a cache that
|
|
286
286
|
has to model each spec's full dependency closure correctly, and getting that wrong produces a stale
|
|
287
287
|
PASS for a test that has since gone vacuous — exactly what the gate is there to prevent. Bad trade
|
|
288
|
-
at
|
|
288
|
+
at 172 mutations.
|
|
289
289
|
|
|
290
290
|
**Decided 2026-10-03 (repo owner): keep the full run.** Measured at 128 mutations, the CI job for
|
|
291
291
|
11.41.6 took **14 minutes**. The trigger to revisit is that wall time, not the mutation count —
|
|
@@ -332,7 +332,7 @@ exactly the environment where the answer matters.
|
|
|
332
332
|
|
|
333
333
|
Worth knowing before optimising the wrong thing: the specs behind all 63 e2e mutations add up to
|
|
334
334
|
**~40 seconds**. The step takes ~740s. The remaining ~700s is paying vitest's startup — process
|
|
335
|
-
spawn, transform, module graph, mongod connect, DB create and drop — once per mutation,
|
|
335
|
+
spawn, transform, module graph, mongod connect, DB create and drop — once per mutation, 172 times.
|
|
336
336
|
That work is largely single-threaded I/O and barely scales with cores: the full registry measures
|
|
337
337
|
**744s on a 12-core laptop and 777s on a 4-vCPU CI runner**.
|
|
338
338
|
|
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-10-06 (v11.42.
|
|
3
|
+
> Auto-generated from source code as of 2026-10-06 (v11.42.7)
|
|
4
4
|
> File: `FRAMEWORK-API.md` — compact, machine-readable API surface for Claude Code
|
|
5
5
|
|
|
6
6
|
## CoreModule.forRoot()
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { INestApplication } from '@nestjs/common';
|
|
2
|
+
import type { OpenAPIObject } from '@nestjs/swagger';
|
|
3
|
+
import type { IServerOptions } from '../interfaces/server-options.interface';
|
|
4
|
+
import type { ISwaggerApiTokenViewOptions, ISwaggerSetupOptions } from '../interfaces/swagger-setup-options.interface';
|
|
5
|
+
export declare const SWAGGER_BEARER_SCHEME = "bearer";
|
|
6
|
+
export declare const SWAGGER_COOKIE_SCHEME = "cookie";
|
|
7
|
+
export declare const SWAGGER_TENANT_HEADER_PARAMETER = "TenantHeader";
|
|
8
|
+
export declare const SWAGGER_API_TOKEN_SCOPES_EXTENSION = "x-api-token-scopes";
|
|
9
|
+
export declare function setupSwagger(app: INestApplication, options: ISwaggerSetupOptions): void;
|
|
10
|
+
export declare function buildSwaggerDocument(app: INestApplication, options: ISwaggerSetupOptions, config?: Partial<IServerOptions>): OpenAPIObject;
|
|
11
|
+
export declare function buildApiTokenSwaggerDocument(document: OpenAPIObject, options?: ISwaggerApiTokenViewOptions, config?: Partial<IServerOptions>): OpenAPIObject;
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SWAGGER_API_TOKEN_SCOPES_EXTENSION = exports.SWAGGER_TENANT_HEADER_PARAMETER = exports.SWAGGER_COOKIE_SCHEME = exports.SWAGGER_BEARER_SCHEME = void 0;
|
|
4
|
+
exports.setupSwagger = setupSwagger;
|
|
5
|
+
exports.buildSwaggerDocument = buildSwaggerDocument;
|
|
6
|
+
exports.buildApiTokenSwaggerDocument = buildApiTokenSwaggerDocument;
|
|
7
|
+
const common_1 = require("@nestjs/common");
|
|
8
|
+
const core_1 = require("@nestjs/core");
|
|
9
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
10
|
+
const core_api_token_helpers_1 = require("../../modules/api-token/core-api-token.helpers");
|
|
11
|
+
const core_api_token_constants_1 = require("../../modules/api-token/core-api-token.constants");
|
|
12
|
+
const better_auth_cookie_prefix_helper_1 = require("../../modules/better-auth/better-auth-cookie-prefix.helper");
|
|
13
|
+
const core_tenant_decorators_1 = require("../../modules/tenant/core-tenant.decorators");
|
|
14
|
+
const core_tenant_helpers_1 = require("../../modules/tenant/core-tenant.helpers");
|
|
15
|
+
const role_enum_1 = require("../enums/role.enum");
|
|
16
|
+
const config_service_1 = require("../services/config.service");
|
|
17
|
+
const cookies_helper_1 = require("./cookies.helper");
|
|
18
|
+
exports.SWAGGER_BEARER_SCHEME = 'bearer';
|
|
19
|
+
exports.SWAGGER_COOKIE_SCHEME = 'cookie';
|
|
20
|
+
exports.SWAGGER_TENANT_HEADER_PARAMETER = 'TenantHeader';
|
|
21
|
+
exports.SWAGGER_API_TOKEN_SCOPES_EXTENSION = 'x-api-token-scopes';
|
|
22
|
+
const HTTP_METHODS = ['delete', 'get', 'head', 'options', 'patch', 'post', 'put', 'trace'];
|
|
23
|
+
const logger = new common_1.Logger('Swagger');
|
|
24
|
+
function setupSwagger(app, options) {
|
|
25
|
+
let document;
|
|
26
|
+
const fullDocument = () => (document ??= buildSwaggerDocument(app, options));
|
|
27
|
+
swagger_1.SwaggerModule.setup(options.path ?? 'swagger', app, fullDocument, {
|
|
28
|
+
...options.customOptions,
|
|
29
|
+
jsonDocumentUrl: options.jsonDocumentUrl ?? '/api-docs-json',
|
|
30
|
+
});
|
|
31
|
+
const view = resolveApiTokenView(options.apiTokenView);
|
|
32
|
+
if (!view.enabled) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
let viewDocument;
|
|
36
|
+
swagger_1.SwaggerModule.setup(view.path, app, () => (viewDocument ??= buildApiTokenSwaggerDocument(fullDocument(), view)), {
|
|
37
|
+
...options.customOptions,
|
|
38
|
+
jsonDocumentUrl: view.jsonDocumentUrl,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function buildSwaggerDocument(app, options, config = config_service_1.ConfigService.configFastButReadOnly ?? {}) {
|
|
42
|
+
if (options.documentOptions?.operationIdFactory) {
|
|
43
|
+
throw new Error('setupSwagger: an own operationIdFactory is not supported — operations are mapped by their default id');
|
|
44
|
+
}
|
|
45
|
+
const apiTokens = (0, core_api_token_helpers_1.resolveApiTokenConfig)(config);
|
|
46
|
+
const multiTenancy = !!config.multiTenancy && config.multiTenancy.enabled !== false;
|
|
47
|
+
const sessionCookie = resolveSessionCookieName(config);
|
|
48
|
+
let builder = new swagger_1.DocumentBuilder()
|
|
49
|
+
.setTitle(options.title)
|
|
50
|
+
.setDescription(options.description ?? '')
|
|
51
|
+
.setVersion(options.version ?? '1.0.0')
|
|
52
|
+
.addBearerAuth({
|
|
53
|
+
description: apiTokens.enabled
|
|
54
|
+
? 'Session token from sign-in, or an API token / signed assertion of an API token.'
|
|
55
|
+
: 'Session token from sign-in.',
|
|
56
|
+
scheme: 'bearer',
|
|
57
|
+
type: 'http',
|
|
58
|
+
}, exports.SWAGGER_BEARER_SCHEME)
|
|
59
|
+
.addSecurityRequirements(exports.SWAGGER_BEARER_SCHEME);
|
|
60
|
+
if (sessionCookie) {
|
|
61
|
+
builder = builder
|
|
62
|
+
.addCookieAuth(sessionCookie, {
|
|
63
|
+
description: `Session cookie set by sign-in (\`${sessionCookie}\`). The browser sends it by itself once you are signed in on this host.`,
|
|
64
|
+
in: 'cookie',
|
|
65
|
+
name: sessionCookie,
|
|
66
|
+
type: 'apiKey',
|
|
67
|
+
}, exports.SWAGGER_COOKIE_SCHEME)
|
|
68
|
+
.addSecurityRequirements(exports.SWAGGER_COOKIE_SCHEME);
|
|
69
|
+
}
|
|
70
|
+
if (options.configureBuilder) {
|
|
71
|
+
builder = options.configureBuilder(builder);
|
|
72
|
+
}
|
|
73
|
+
const document = swagger_1.SwaggerModule.createDocument(app, builder.build(), {
|
|
74
|
+
autoTagControllers: true,
|
|
75
|
+
deepScanRoutes: true,
|
|
76
|
+
...options.documentOptions,
|
|
77
|
+
});
|
|
78
|
+
const headerName = canonicalHeaderName(config.multiTenancy?.headerName ?? 'x-tenant-id');
|
|
79
|
+
if (multiTenancy) {
|
|
80
|
+
document.components = document.components ?? {};
|
|
81
|
+
document.components.parameters = {
|
|
82
|
+
...document.components.parameters,
|
|
83
|
+
[exports.SWAGGER_TENANT_HEADER_PARAMETER]: tenantHeaderParameter(headerName, apiTokens),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const handlers = indexHandlers(app);
|
|
87
|
+
forEachOperation(document, (path, method, operation) => {
|
|
88
|
+
const reference = resolveHandler(operation.operationId, handlers);
|
|
89
|
+
if (!reference) {
|
|
90
|
+
logger.warn(`No handler found for operation ${operation.operationId ?? `${method.toUpperCase()} ${path}`}`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const access = describeAccess(reference, multiTenancy);
|
|
94
|
+
if (access.isPublic) {
|
|
95
|
+
operation.security = [];
|
|
96
|
+
}
|
|
97
|
+
if (apiTokens.enabled) {
|
|
98
|
+
if (access.scopes?.length) {
|
|
99
|
+
operation[exports.SWAGGER_API_TOKEN_SCOPES_EXTENSION] = [...access.scopes];
|
|
100
|
+
}
|
|
101
|
+
operation.description = appendLine(operation.description, apiTokenLine(access.scopes));
|
|
102
|
+
}
|
|
103
|
+
if (multiTenancy && !access.isPublic && !access.skipsTenantHeader && !hasHeaderParameter(operation, headerName)) {
|
|
104
|
+
operation.parameters = [
|
|
105
|
+
...(operation.parameters ?? []),
|
|
106
|
+
{ $ref: `#/components/parameters/${exports.SWAGGER_TENANT_HEADER_PARAMETER}` },
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
if (options.operationTags) {
|
|
110
|
+
const tags = options.operationTags({
|
|
111
|
+
controller: reference.controller.name,
|
|
112
|
+
handler: reference.handlerName,
|
|
113
|
+
isPublic: access.isPublic,
|
|
114
|
+
method,
|
|
115
|
+
path,
|
|
116
|
+
scopes: access.scopes,
|
|
117
|
+
tags: [...(operation.tags ?? [])],
|
|
118
|
+
});
|
|
119
|
+
if (tags) {
|
|
120
|
+
operation.tags = tags;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
document.tags = orderTags(document, options.tags);
|
|
125
|
+
return document;
|
|
126
|
+
}
|
|
127
|
+
function buildApiTokenSwaggerDocument(document, options = {}, config = config_service_1.ConfigService.configFastButReadOnly ?? {}) {
|
|
128
|
+
const keepsTenantHeader = (0, core_api_token_helpers_1.resolveApiTokenConfig)(config).userTokens;
|
|
129
|
+
const view = structuredClone(document);
|
|
130
|
+
view.info = {
|
|
131
|
+
...view.info,
|
|
132
|
+
description: options.description ?? view.info.description,
|
|
133
|
+
title: options.title ?? `${view.info.title} — API tokens`,
|
|
134
|
+
};
|
|
135
|
+
view.security = [{ [exports.SWAGGER_BEARER_SCHEME]: [] }];
|
|
136
|
+
const paths = {};
|
|
137
|
+
for (const [path, item] of Object.entries(view.paths)) {
|
|
138
|
+
const kept = {};
|
|
139
|
+
for (const method of HTTP_METHODS) {
|
|
140
|
+
const operation = item[method];
|
|
141
|
+
if (!operation?.[exports.SWAGGER_API_TOKEN_SCOPES_EXTENSION]?.length) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
operation.security = [{ [exports.SWAGGER_BEARER_SCHEME]: [] }];
|
|
145
|
+
if (!keepsTenantHeader) {
|
|
146
|
+
operation.parameters = operation.parameters?.filter((parameter) => !isRef(parameter) || parameter.$ref !== `#/components/parameters/${exports.SWAGGER_TENANT_HEADER_PARAMETER}`);
|
|
147
|
+
}
|
|
148
|
+
kept[method] = operation;
|
|
149
|
+
}
|
|
150
|
+
if (Object.keys(kept).length) {
|
|
151
|
+
paths[path] = { ...pathLevelFields(item), ...kept };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
view.paths = paths;
|
|
155
|
+
if (view.components) {
|
|
156
|
+
const { parameters, securitySchemes } = view.components;
|
|
157
|
+
if (parameters && !keepsTenantHeader) {
|
|
158
|
+
delete parameters[exports.SWAGGER_TENANT_HEADER_PARAMETER];
|
|
159
|
+
}
|
|
160
|
+
if (securitySchemes) {
|
|
161
|
+
view.components.securitySchemes = { [exports.SWAGGER_BEARER_SCHEME]: securitySchemes[exports.SWAGGER_BEARER_SCHEME] };
|
|
162
|
+
}
|
|
163
|
+
pruneUnusedSchemas(view);
|
|
164
|
+
}
|
|
165
|
+
const used = new Set();
|
|
166
|
+
forEachOperation(view, (_path, _method, operation) => operation.tags?.forEach((tag) => used.add(tag)));
|
|
167
|
+
view.tags = view.tags?.filter((tag) => used.has(tag.name));
|
|
168
|
+
return view;
|
|
169
|
+
}
|
|
170
|
+
function describeAccess(reference, multiTenancy) {
|
|
171
|
+
const handlerRoles = Reflect.getMetadata('roles', reference.handler);
|
|
172
|
+
const classRoles = Reflect.getMetadata('roles', reference.controller);
|
|
173
|
+
const roles = (0, core_tenant_helpers_1.mergeRolesMetadata)([handlerRoles, classRoles]);
|
|
174
|
+
const systemRoles = handlerRoles?.length ? handlerRoles : roles;
|
|
175
|
+
const isPublic = !roles.some(Boolean) ||
|
|
176
|
+
(roles.includes(role_enum_1.RoleEnum.S_EVERYONE) && (!multiTenancy || systemRoles.includes(role_enum_1.RoleEnum.S_EVERYONE)));
|
|
177
|
+
const scopes = Reflect.getMetadata(core_api_token_constants_1.API_TOKEN_SCOPES_KEY, reference.handler) ??
|
|
178
|
+
Reflect.getMetadata(core_api_token_constants_1.API_TOKEN_SCOPES_KEY, reference.controller);
|
|
179
|
+
const skipsTenantHeader = !!(Reflect.getMetadata(core_tenant_decorators_1.SKIP_TENANT_CHECK_KEY, reference.handler) ??
|
|
180
|
+
Reflect.getMetadata(core_tenant_decorators_1.SKIP_TENANT_CHECK_KEY, reference.controller));
|
|
181
|
+
return { isPublic, scopes: scopes?.length ? scopes : undefined, skipsTenantHeader };
|
|
182
|
+
}
|
|
183
|
+
function indexHandlers(app) {
|
|
184
|
+
const index = new Map();
|
|
185
|
+
for (const module of app.get(core_1.ModulesContainer).values()) {
|
|
186
|
+
for (const wrapper of module.controllers.values()) {
|
|
187
|
+
const controller = wrapper.metatype;
|
|
188
|
+
if (!controller?.name) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
const known = index.get(controller.name) ?? [];
|
|
192
|
+
if (!known.includes(controller)) {
|
|
193
|
+
index.set(controller.name, [...known, controller]);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return index;
|
|
198
|
+
}
|
|
199
|
+
function resolveHandler(operationId, index) {
|
|
200
|
+
if (!operationId) {
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
for (let separator = operationId.indexOf('_'); separator > 0; separator = operationId.indexOf('_', separator + 1)) {
|
|
204
|
+
const controllers = index.get(operationId.slice(0, separator));
|
|
205
|
+
if (!controllers) {
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (controllers.length > 1) {
|
|
209
|
+
logger.warn(`Controller name ${controllers[0].name} is used by ${controllers.length} classes; ${operationId} is not enriched`);
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
const controller = controllers[0];
|
|
213
|
+
const rest = operationId.slice(separator + 1).replace(/\[\d+\]/g, '');
|
|
214
|
+
for (const handlerName of [rest, rest.replace(/_[^_]+$/, '')]) {
|
|
215
|
+
const handler = controller.prototype[handlerName];
|
|
216
|
+
if (typeof handler === 'function') {
|
|
217
|
+
return { controller, handler: handler, handlerName };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
function resolveApiTokenView(option) {
|
|
224
|
+
const options = typeof option === 'object' && option !== null ? option : {};
|
|
225
|
+
return {
|
|
226
|
+
description: options.description,
|
|
227
|
+
enabled: option === true || (typeof option === 'object' && option !== null && option.enabled !== false),
|
|
228
|
+
jsonDocumentUrl: options.jsonDocumentUrl ?? '/api-docs-api-tokens-json',
|
|
229
|
+
path: options.path ?? 'swagger-api-tokens',
|
|
230
|
+
title: options.title,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
function resolveSessionCookieName(config) {
|
|
234
|
+
const betterAuth = config.betterAuth;
|
|
235
|
+
if (betterAuth === false || (typeof betterAuth === 'object' && betterAuth?.enabled === false)) {
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
if (!(0, cookies_helper_1.isCookiesEnabled)(config.cookies)) {
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
return (0, better_auth_cookie_prefix_helper_1.resolveBetterAuthSessionCookieName)(typeof betterAuth === 'object' ? (betterAuth.basePath ?? '/iam') : '/iam');
|
|
242
|
+
}
|
|
243
|
+
function tenantHeaderParameter(name, apiTokens) {
|
|
244
|
+
return {
|
|
245
|
+
description: [
|
|
246
|
+
'Company (tenant) the request acts in.',
|
|
247
|
+
'Session callers: required on company routes; on routes open to every signed-in user it is optional and validated when sent.',
|
|
248
|
+
apiTokens.tenantTokens
|
|
249
|
+
? 'API tokens of a company carry their company and may omit it; when sent, it must name that company.'
|
|
250
|
+
: '',
|
|
251
|
+
apiTokens.userTokens
|
|
252
|
+
? 'A personal API token chooses the company like a session; one restricted to a company may omit it.'
|
|
253
|
+
: '',
|
|
254
|
+
]
|
|
255
|
+
.filter(Boolean)
|
|
256
|
+
.join(' '),
|
|
257
|
+
in: 'header',
|
|
258
|
+
name,
|
|
259
|
+
required: false,
|
|
260
|
+
schema: { type: 'string' },
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function apiTokenLine(scopes) {
|
|
264
|
+
return scopes?.length
|
|
265
|
+
? `**API tokens:** allowed with scope ${scopes.map((scope) => `\`${scope}\``).join(' or ')}.`
|
|
266
|
+
: '**API tokens:** not allowed on this route.';
|
|
267
|
+
}
|
|
268
|
+
function appendLine(description, line) {
|
|
269
|
+
return description ? `${description}\n\n${line}` : line;
|
|
270
|
+
}
|
|
271
|
+
function canonicalHeaderName(name) {
|
|
272
|
+
return name
|
|
273
|
+
.split('-')
|
|
274
|
+
.map((part) => (part ? part[0].toUpperCase() + part.slice(1).toLowerCase() : part))
|
|
275
|
+
.join('-');
|
|
276
|
+
}
|
|
277
|
+
function hasHeaderParameter(operation, name) {
|
|
278
|
+
return !!operation.parameters?.some((parameter) => !isRef(parameter) && parameter.in === 'header' && parameter.name.toLowerCase() === name.toLowerCase());
|
|
279
|
+
}
|
|
280
|
+
function isRef(value) {
|
|
281
|
+
return typeof value === 'object' && value !== null && '$ref' in value;
|
|
282
|
+
}
|
|
283
|
+
function forEachOperation(document, visit) {
|
|
284
|
+
for (const [path, item] of Object.entries(document.paths ?? {})) {
|
|
285
|
+
for (const method of HTTP_METHODS) {
|
|
286
|
+
const operation = item[method];
|
|
287
|
+
if (operation) {
|
|
288
|
+
visit(path, method, operation);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
function pathLevelFields(item) {
|
|
294
|
+
const fields = { ...item };
|
|
295
|
+
for (const method of HTTP_METHODS) {
|
|
296
|
+
delete fields[method];
|
|
297
|
+
}
|
|
298
|
+
return fields;
|
|
299
|
+
}
|
|
300
|
+
function orderTags(document, configured) {
|
|
301
|
+
const used = [];
|
|
302
|
+
forEachOperation(document, (_path, _method, operation) => {
|
|
303
|
+
for (const tag of operation.tags ?? []) {
|
|
304
|
+
if (!used.includes(tag)) {
|
|
305
|
+
used.push(tag);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
const existing = new Map((document.tags ?? []).map((tag) => [tag.name, tag]));
|
|
310
|
+
const ordered = [];
|
|
311
|
+
for (const tag of configured ?? []) {
|
|
312
|
+
if (used.includes(tag.name)) {
|
|
313
|
+
ordered.push({ ...existing.get(tag.name), ...tag });
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
for (const name of used) {
|
|
317
|
+
if (!ordered.some((tag) => tag.name === name)) {
|
|
318
|
+
ordered.push(existing.get(name) ?? { name });
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return ordered;
|
|
322
|
+
}
|
|
323
|
+
function pruneUnusedSchemas(document) {
|
|
324
|
+
const schemas = document.components?.schemas;
|
|
325
|
+
if (!schemas) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
const prefix = '#/components/schemas/';
|
|
329
|
+
const reached = new Set();
|
|
330
|
+
const pending = [
|
|
331
|
+
document.paths,
|
|
332
|
+
document.components?.parameters,
|
|
333
|
+
document.components?.requestBodies,
|
|
334
|
+
document.components?.responses,
|
|
335
|
+
];
|
|
336
|
+
while (pending.length) {
|
|
337
|
+
const value = pending.pop();
|
|
338
|
+
if (Array.isArray(value)) {
|
|
339
|
+
pending.push(...value);
|
|
340
|
+
}
|
|
341
|
+
else if (typeof value === 'object' && value !== null) {
|
|
342
|
+
for (const [key, child] of Object.entries(value)) {
|
|
343
|
+
if (key === '$ref' && typeof child === 'string' && child.startsWith(prefix)) {
|
|
344
|
+
const name = child.slice(prefix.length);
|
|
345
|
+
if (!reached.has(name)) {
|
|
346
|
+
reached.add(name);
|
|
347
|
+
pending.push(schemas[name]);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
pending.push(child);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
for (const name of Object.keys(schemas)) {
|
|
357
|
+
if (!reached.has(name)) {
|
|
358
|
+
delete schemas[name];
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
//# sourceMappingURL=swagger.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swagger.helper.js","sourceRoot":"","sources":["../../../../src/core/common/helpers/swagger.helper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { DocumentBuilder, SwaggerCustomOptions, SwaggerDocumentOptions } from '@nestjs/swagger';
|
|
2
|
+
export interface ISwaggerOperationInfo {
|
|
3
|
+
controller: string;
|
|
4
|
+
handler: string;
|
|
5
|
+
isPublic: boolean;
|
|
6
|
+
method: string;
|
|
7
|
+
path: string;
|
|
8
|
+
scopes?: string[];
|
|
9
|
+
tags: string[];
|
|
10
|
+
}
|
|
11
|
+
export interface ISwaggerApiTokenViewOptions {
|
|
12
|
+
description?: string;
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
jsonDocumentUrl?: string;
|
|
15
|
+
path?: string;
|
|
16
|
+
title?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ISwaggerSetupOptions {
|
|
19
|
+
apiTokenView?: boolean | ISwaggerApiTokenViewOptions;
|
|
20
|
+
configureBuilder?: (builder: DocumentBuilder) => DocumentBuilder;
|
|
21
|
+
customOptions?: Omit<SwaggerCustomOptions, 'jsonDocumentUrl' | 'yamlDocumentUrl'>;
|
|
22
|
+
description?: string;
|
|
23
|
+
documentOptions?: Omit<SwaggerDocumentOptions, 'operationIdFactory'>;
|
|
24
|
+
jsonDocumentUrl?: string;
|
|
25
|
+
operationTags?: (operation: ISwaggerOperationInfo) => string[] | undefined;
|
|
26
|
+
path?: string;
|
|
27
|
+
tags?: {
|
|
28
|
+
description?: string;
|
|
29
|
+
name: string;
|
|
30
|
+
}[];
|
|
31
|
+
title: string;
|
|
32
|
+
version?: string;
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swagger-setup-options.interface.js","sourceRoot":"","sources":["../../../../src/core/common/interfaces/swagger-setup-options.interface.ts"],"names":[],"mappings":""}
|
|
@@ -18,9 +18,11 @@ export declare class CoreBodyParserInitializer implements OnModuleInit {
|
|
|
18
18
|
protected getConfig(): IBodyParserConfig | undefined;
|
|
19
19
|
protected getRouterStack(): ExpressLayer[] | undefined;
|
|
20
20
|
protected isGlobalParserLayer(layer: ExpressLayer | undefined, type: CoreBodyParserType): boolean;
|
|
21
|
+
protected isBodyParserEnabled(): boolean;
|
|
21
22
|
protected isRawBodyEnabled(): boolean;
|
|
22
23
|
protected resolveLimit(type: CoreBodyParserType, value: unknown): number | undefined;
|
|
23
24
|
protected translateError(type: CoreBodyParserType, error: unknown, req: Request): unknown;
|
|
25
|
+
protected warnMissingGlobalParser(type: CoreBodyParserType, stack: ExpressLayer[], limit: number | undefined): void;
|
|
24
26
|
protected wrapParser(type: CoreBodyParserType, parser: RequestHandler): RequestHandler;
|
|
25
27
|
}
|
|
26
28
|
export {};
|
|
@@ -53,9 +53,8 @@ let CoreBodyParserInitializer = CoreBodyParserInitializer_1 = class CoreBodyPars
|
|
|
53
53
|
for (const type of ['json', 'urlencoded']) {
|
|
54
54
|
const limit = this.resolveLimit(type, config?.[type]?.limit);
|
|
55
55
|
const layers = stack.filter((layer) => this.isGlobalParserLayer(layer, type));
|
|
56
|
-
if (
|
|
57
|
-
this.
|
|
58
|
-
'(was the app created with `bodyParser: false`?) — the limit has no effect.');
|
|
56
|
+
if (!layers.length) {
|
|
57
|
+
this.warnMissingGlobalParser(type, stack, limit);
|
|
59
58
|
continue;
|
|
60
59
|
}
|
|
61
60
|
for (const layer of layers) {
|
|
@@ -85,6 +84,11 @@ let CoreBodyParserInitializer = CoreBodyParserInitializer_1 = class CoreBodyPars
|
|
|
85
84
|
isGlobalParserLayer(layer, type) {
|
|
86
85
|
return layer?.slash === true && typeof layer.handle === 'function' && layer.handle.name === PARSER_NAMES[type];
|
|
87
86
|
}
|
|
87
|
+
isBodyParserEnabled() {
|
|
88
|
+
const container = this.moduleRef
|
|
89
|
+
?.container;
|
|
90
|
+
return container?.contextOptions?.bodyParser !== false;
|
|
91
|
+
}
|
|
88
92
|
isRawBodyEnabled() {
|
|
89
93
|
const container = this.moduleRef
|
|
90
94
|
?.container;
|
|
@@ -114,6 +118,22 @@ let CoreBodyParserInitializer = CoreBodyParserInitializer_1 = class CoreBodyPars
|
|
|
114
118
|
`raise \`bodyParser.${type}.limit\` in the server options.`);
|
|
115
119
|
return new common_1.PayloadTooLargeException(`${error_codes_1.ErrorCode.REQUEST_BODY_TOO_LARGE} [${sizeText}limit ${details.limit} bytes]`);
|
|
116
120
|
}
|
|
121
|
+
warnMissingGlobalParser(type, stack, limit) {
|
|
122
|
+
const name = PARSER_NAMES[type];
|
|
123
|
+
const shadowed = stack.some((layer) => layer?.slash !== true && layer?.handle?.name === name);
|
|
124
|
+
if (shadowed && this.isBodyParserEnabled()) {
|
|
125
|
+
this.logger.warn(`No global ${type} body parser is registered: NestJS skips its own when a layer named \`${name}\` ` +
|
|
126
|
+
`already exists, and a path-scoped \`${type}()\` parser registered before \`app.init()\` counts as one. ` +
|
|
127
|
+
`Every request outside that path reaches its handler with an EMPTY body. Register the global parser ` +
|
|
128
|
+
`in main.ts as well — \`server.useBodyParser('${type}')\` — a configured \`bodyParser.${type}.limit\` ` +
|
|
129
|
+
'is applied to it.');
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (limit !== undefined) {
|
|
133
|
+
this.logger.warn(`bodyParser.${type}.limit is configured, but no global ${type} body parser is registered ` +
|
|
134
|
+
'(was the app created with `bodyParser: false`?) — the limit has no effect.');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
117
137
|
wrapParser(type, parser) {
|
|
118
138
|
const wrapped = (req, res, next) => parser(req, res, (error) => (error ? next(this.translateError(type, error, req)) : next()));
|
|
119
139
|
Object.defineProperty(wrapped, 'name', { value: PARSER_NAMES[type] });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core-body-parser.initializer.js","sourceRoot":"","sources":["../../../../src/core/common/services/core-body-parser.initializer.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAuCA,wCAaC;AApDD,2CAAsG;AACtG,uCAA0D;AAC1D,qCAA2C;AAE3C,sEAAiE;AAEjE,qDAAiD;AAWjD,MAAM,YAAY,GAAuC,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC;AAGhH,MAAM,YAAY,GAA2B,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;AAmB9F,SAAgB,cAAc,CAAC,KAAc;IAC3C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9E,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAG,oCAAoC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACtE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAC3F,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACxC,CAAC;AAoBM,IAAM,yBAAyB,iCAA/B,MAAM,yBAAyB;IAIH;IACA;IAJd,MAAM,GAAG,IAAI,eAAM,CAAC,2BAAyB,CAAC,IAAI,CAAC,CAAC;IAEvE,YACiC,eAAiC,EACjC,SAAqB;QADrB,oBAAe,GAAf,eAAe,CAAkB;QACjC,cAAS,GAAT,SAAS,CAAY;IACnD,CAAC;IAEJ,YAAY;QACV,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QACpC,IAAI,CAAC,KAAK,EAAE,CAAC;YAEX,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAChC,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,YAAY,CAAU,EAAE,CAAC;YACnD,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;YAC7D,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;YAE9E,IAAI,
|
|
1
|
+
{"version":3,"file":"core-body-parser.initializer.js","sourceRoot":"","sources":["../../../../src/core/common/services/core-body-parser.initializer.ts"],"names":[],"mappings":"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"}
|