@lenne.tech/nest-server 11.39.0 → 11.40.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.
@@ -333,6 +333,7 @@ This pattern is currently applied to:
333
333
  | 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 |
334
334
  | 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` |
335
335
  | 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 |
336
+ | 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()` |
336
337
  | 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; 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 } })` |
337
338
 
338
339
  ## Module Override Pattern (via `ICoreModuleOverrides`)
@@ -83,6 +83,8 @@ override async signIn(...): Promise<Auth> {
83
83
  |------------|--------|---------|
84
84
  | `CoreAuthResolver` | `checkLegacyGraphQLEnabled(name)` | Throws HTTP 410 if legacy endpoints disabled |
85
85
  | `CoreAuthController` | `checkLegacyRESTEnabled(name)` | Throws HTTP 410 if legacy endpoints disabled |
86
+ | `OpenAiCompatibleProvider` | `resolveAllowedBaseUrlHosts()` | Normalises the SSRF egress allowlist (CSV string, case, trailing dot) and reports a malformed value. An override of `assertBaseUrlAllowed()` that re-reads `ConfigService` directly silently loses all of it — including the string form the framework's own `NSC__` mapping produces, which is the shape that used to switch the control off |
87
+ | `OpenAiCompatibleProvider` | `assertBaseUrlAllowed(url)` | Call it before ANY new outbound `fetch` you add to a provider. It already guards `chat()`, `probe()` and `probeContextWindow()`; a fourth path that forgets it is a hole the allowlist's own tests cannot see unless they assert on `fetch` |
86
88
 
87
89
  **Rule**: When you override a method, check if the parent calls any `protected` helper methods. If so, call them in your override too.
88
90
 
@@ -151,7 +151,7 @@ Two ordering rules, both enforced by the contract test:
151
151
  | Rule | Why |
152
152
  |------|-----|
153
153
  | `packageManager` is exact (`x.y.z+sha512.<hash>`), never a range | Same fixed-version rule as dependencies; corepack rejects ranges outright |
154
- | `engines.pnpm` tracks the pin's major (`^<major>.0.0`) | A soft gate that warns pnpm 10 users. It is not a pin and cannot tell CI what to install |
154
+ | `engines.pnpm` tracks the pin's major (`^<major>.0.0`) | A soft gate that warns pnpm 10 users. It is not a pin and cannot tell CI what to install. Note it is deliberately looser than what the check chains rely on: `pnpm peers check` is a pnpm 11 subcommand, and `^11.0.0` does not guarantee the minor that introduced it. The real guarantee is `packageManager`, which is exact — this range is not the place to encode a floor |
155
155
  | Never declare `devEngines.packageManager` | npm/npx abort with `EBADDEVENGINES`; corepack rejects ranges inside it |
156
156
  | Never pass `version:` to `pnpm/action-setup` | Two sources drift; the action hard-errors on a mismatch |
157
157
  | Never `RUN corepack …` | Absent on Node >= 25 |
@@ -168,7 +168,8 @@ Two ordering rules, both enforced by the contract test:
168
168
 
169
169
  Package overrides live in the `overrides:` section of **`pnpm-workspace.yaml`** (they moved out of `package.json`'s `pnpm.overrides` in the pnpm 11 upgrade). They force transitive dependencies to a security-patched version.
170
170
 
171
- **Keep the set minimal.** On the pnpm 11 upgrade the list was pruned from 36 to the 9 still load-bearing — an override is only necessary if removing it lets the package resolve back INTO its vulnerable range (verify with a with/without lockfile diff; `pnpm audit` is the arbiter). Each surviving entry carries its CVE rationale as a comment. Remove an entry once its parent dependency ships a fixed version.
171
+ **Keep the set minimal.** On the pnpm 11 upgrade the list was pruned from 36 to the 9 then still
172
+ load-bearing (it has since grown back to 17 as new advisories landed) — an override is only necessary if removing it lets the package resolve back INTO its vulnerable range (verify with a with/without lockfile diff; `pnpm audit` is the arbiter). Each surviving entry carries its CVE rationale as a comment. Remove an entry once its parent dependency ships a fixed version.
172
173
 
173
174
  ### Rule: Override Targets MUST Be Fixed Versions
174
175
 
@@ -263,6 +264,16 @@ The reliable tells are narrower:
263
264
  3. **The lockfile resolves two versions of the package inside one major.** Beware `@types/x`, which
264
265
  looks like a second resolution of `x` and is not.
265
266
 
267
+ **This is automated now — `pnpm run check:overrides`.** The guard (`scripts/check-overrides.mjs`)
268
+ cross-references every `overrides:` entry against a live `pnpm audit` report and reports four
269
+ classes: **TOO LOW** (the override resolves and still delivers a version the advisory covers — modes
270
+ 1 and 2 above), **NOT MATCHING** (the selector no longer reaches the path it was written for), plus
271
+ **NO FIX** and **UNUSED** as warnings. It runs inside `check`, `check:fix`, `check:naf` and
272
+ `check:raw`, and in CI on both `build.yml` and `publish.yml`. The three tells above are still how you
273
+ *read* a report by hand; the guard is what makes sure somebody does. `--audit-file` and
274
+ `--advisory-file` make a run reproducible offline, and CI passes `--audit-file` so the
275
+ cannot-obtain-a-report skip (correct on a laptop, a silent pass on a runner) is unreachable there.
276
+
266
277
  **The fix in both cases is one entry, floored below the current patch line, targeting a version at
267
278
  or above it:**
268
279
 
@@ -280,6 +291,44 @@ or above it:**
280
291
  `ERR_PNPM_NO_MATURE_MATCHING_VERSION`. Take the oldest version that clears every advisory — which
281
292
  is the right instinct regardless of the policy.
282
293
 
294
+ ### Suppressions age the same way, and worse
295
+
296
+ `auditConfig.ignoreGhsas` in `pnpm-workspace.yaml` suppresses an advisory outright. It is the other
297
+ half of the problem above, and the blinder half.
298
+
299
+ An override at least stays visible: `pnpm audit` keeps reporting its package, so a stale entry can be
300
+ caught by reading the report against the file. **A suppressed advisory is removed from
301
+ `pnpm audit --json` entirely** — `advisories` drops it and `muted` comes back empty. Once a GHSA is
302
+ listed there, no audit run ever mentions it again. If upstream ships a fix tomorrow, nothing says so.
303
+
304
+ That is not hypothetical either. `GHSA-mh99-v99m-4gvg` was suppressed on 2026-07-28 with a
305
+ justification that was correct in every detail: the newest 1.x was 1.1.16 and carried no length
306
+ guard, and the one remaining path could not be lifted. **1.1.17 — the backport the entry said did not
307
+ exist — was published on 2026-07-29, one day later.** The entry sat obsolete for five weeks, and
308
+ nothing in the repo could have said so.
309
+
310
+ **Rules for an entry here:**
311
+
312
+ 1. **Name the advisory, the affected path, and why it cannot be fixed** — not just why it is
313
+ tolerable.
314
+ 2. **Record what you verified and when**, with a re-verification trigger ("re-check when @nestjs/cli
315
+ drops fork-ts-checker-webpack-plugin"). A justification without a date cannot be audited later.
316
+ 3. **Assume it will stop being true without telling you.** Ask, before adding it: *what will notice
317
+ when this expires?* If the answer is "nothing", the entry is a liability regardless of how good
318
+ today's reasoning is.
319
+ 4. **Prefer an override.** A suppression is the last resort, for an advisory with no patched version
320
+ anywhere. A drifted override is at least still visible.
321
+
322
+ `pnpm run check:overrides` re-checks every listed GHSA against the GitHub Advisory API and **fails**
323
+ on `FIX AVAILABLE` (a `first_patched_version` now exists) or on a withdrawn advisory. An unreachable
324
+ API is reported as `UNVERIFIED` and tolerated locally — but **fails under `CI`**, because a skip
325
+ nobody reads is indistinguishable from a check that ran.
326
+
327
+ One consequence worth knowing before you reach for this mechanism: the guard fires when the advisory
328
+ has a patched version for **any** affected range. That makes `ignoreGhsas` nearly unusable for an
329
+ advisory that is fixed *somewhere* but unfixable on *your* path — which is the honest outcome, since
330
+ that case is an override problem, not a suppression problem.
331
+
283
332
  ### Safe Override Workflow
284
333
 
285
334
  When adding an override to fix a vulnerability:
@@ -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 45 that need no MongoDB
269
+ pnpm run check:mutations -- --no-infra # only the 63 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,10 @@ when the registry, a vitest config or a setup file changed, since those can move
285
285
  commit, so selective re-running would save ~10 minutes a release. The price is a cache that has to
286
286
  model each spec's full dependency closure correctly, and getting that wrong produces a stale PASS
287
287
  for a test that has since gone vacuous — exactly what the gate is there to prevent. Bad trade
288
- at 91 mutations. Worth revisiting around 100, where the full run approaches half an hour.
288
+ at 109 mutations past the threshold this paragraph has carried since the gate was written,
289
+ now reached exactly. The full run is approaching half an hour. **The re-evaluation is due now**: the
290
+ next person to add a mutation should decide whether selective re-running has become worth its
291
+ failure mode (a stale PASS for a test that has since gone vacuous), not bump this number again.
289
292
 
290
293
  Not part of `pnpm run check` — it edits source and re-runs whole e2e suites. It belongs in review
291
294
  and on the publish path. It is also reachable on demand, without cutting a release:
@@ -326,7 +329,7 @@ exactly the environment where the answer matters.
326
329
 
327
330
  Worth knowing before optimising the wrong thing: the specs behind all 46 e2e mutations add up to
328
331
  **~40 seconds**. The step takes ~740s. The remaining ~700s is paying vitest's startup — process
329
- spawn, transform, module graph, mongod connect, DB create and drop — once per mutation, 91 times.
332
+ spawn, transform, module graph, mongod connect, DB create and drop — once per mutation, 109 times.
330
333
  That work is largely single-threaded I/O and barely scales with cores: the full registry measures
331
334
  **744s on a 12-core laptop and 777s on a 4-vCPU CI runner**.
332
335
 
@@ -370,6 +373,155 @@ When a change adds or edits a test that claims to fix or pin a bug:
370
373
  4. **"Is the mutation the defect, or a proxy for it?"** A mutation that breaks everything proves
371
374
  nothing about the specific behaviour.
372
375
 
376
+ ## `disableConsoleIntercept` — why both runners set it
377
+
378
+ **Rule: both vitest configs in THIS repo set `disableConsoleIntercept: true`, because both were
379
+ measured and both showed exposure. Do not remove it to get per-file console attribution back
380
+ without reading this first — and do not copy it into another repo without measuring there.**
381
+
382
+ It is the fix for an `EnvironmentTeardownError` that failed `pnpm run check` roughly **1 run in
383
+ 10**, with every test green:
384
+
385
+ ```
386
+ EnvironmentTeardownError: [vitest-worker]: Closing rpc while "onUserConsoleLog" was pending
387
+ Test Files 108 passed (108)
388
+ Tests 2300 passed | 1 skipped (2301)
389
+ Errors 1 error
390
+ ```
391
+
392
+ ### The mechanism
393
+
394
+ vitest normally replaces `globalThis.console` in every worker (`setupConsoleLogSpy()`) and
395
+ forwards each write to the main thread as an `onUserConsoleLog` RPC. At worker teardown
396
+ `execute()` does **not** await those calls — it rejects whatever is still in flight:
397
+
398
+ ```js
399
+ rpc.$rejectPendingCalls(({ method, reject }) =>
400
+ reject(new EnvironmentTeardownError(`Closing rpc while "${method}" was pending`)))
401
+ ```
402
+
403
+ The rejection surfaces as an unhandled error and fails the run. So a console write from the last
404
+ test of a file can lose a race against its own cleanup.
405
+
406
+ `disableConsoleIntercept: true` skips `setupConsoleLogSpy()` entirely, so the custom console is
407
+ never installed. Worker-side, `rpc.onUserConsoleLog` has exactly ONE caller — `sendLog()` inside
408
+ that console (`vitest/dist/chunks/console.*.js`); every other reference is main-process reporter
409
+ code. No spy, no caller, nothing that can be pending. **That is a structural fix, not a reduced
410
+ probability** — which matters, because the rate is load-dependent and no number of green runs
411
+ would have proved it.
412
+
413
+ ### The cost, and why it is not what it looks like
414
+
415
+ The obvious reading — "you lose the `stdout | <file>` prefix" — is wrong, and both configs said so
416
+ until it was measured. With the intercept ON, the default reporter **swallows console output from
417
+ PASSING tests entirely** in a piped run (which is how CI and every piped `check` runs). Removing it
418
+ does not strip a prefix; it makes previously invisible output appear:
419
+
420
+ ```
421
+ nest-server unit disableConsoleIntercept: false -> 0 visible lines
422
+ disableConsoleIntercept: true -> 8-9 visible lines
423
+ ```
424
+
425
+ The range is not sloppiness: three of those lines are the rate-limit-store capacity warning, whose
426
+ count depends on how many counters a run happens to create, so the total moves between runs. Quote a
427
+ range when a measurement varies — a single number invites the next reader to treat a normal 8 as a
428
+ regression from 9 and go looking for it.
429
+
430
+ **And count the writes, not one phrasing of them.** A first attempt at re-measuring this grepped for
431
+ `Configured for|No local config` and reported **1**, because the other seven lines are a hub-buffer
432
+ warning, a ConfigService merge notice, three rate-limit warnings and two dev auth URLs — none of
433
+ which match those words. That reads as "no exposure" and is the same artefact as counting reporter
434
+ output, arrived at from a different direction. Diff a flag-off run against a flag-on run instead;
435
+ the difference IS the answer, and it cannot be narrowed by a pattern.
436
+
437
+ Measure by flipping the value IN THE CONFIG. A CLI override does not win against a config value —
438
+ a first attempt at this measurement was worthless for exactly that reason.
439
+
440
+ **And it does not point the same way in every suite.** In an e2e config, where the reporter DOES
441
+ print passing-test output, the intercept adds a header line per write, so removing it roughly
442
+ halves the volume. Same flag, opposite ledger.
443
+
444
+ That direction is the finding; do not quote a figure for it. The `57 → 37` this line used to carry
445
+ came from a comment in the starter's own config (`vitest-e2e.config.ts:96`, "this run went from 57
446
+ visible lines to 37") that nobody here has re-run, and whose scope is ambiguous — the paragraph
447
+ above it discusses a single-spec run, so the numbers may describe one file or the whole suite.
448
+ **Where a number has not been measured, state the direction and stop.** The claim that matters —
449
+ that the ledger flips in an e2e config, because that reporter does print passing-test output — needs
450
+ no figure at all, and a figure nobody can source invites the next reader to treat it as a baseline.
451
+
452
+ ### Not a rule to apply blindly — measure both sides
453
+
454
+ `nest-server` sets it in both runners because both showed exposure. That is a finding here, not a
455
+ default. `nest-server-starter` deliberately sets it ONLY in the e2e config, `nuxt-base-starter`
456
+ and `offers` set it nowhere — each after measuring.
457
+
458
+ The trap is the measurement itself. Counting `grep -cE '^(stdout|stderr) \| '` reports what the
459
+ REPORTER PRINTS, not the RPC traffic — so a suite with 114 suppressed writes measures 0 and looks
460
+ immune. That artefact produced a wrong "zero exposure" verdict in the starter before
461
+ `nuxt-base-starter` caught it. The honest procedure is:
462
+
463
+ 1. Exposure — does the suite make `console.*` calls at all? (Nest `Logger` output does not count;
464
+ it bypasses the intercept.)
465
+ 2. Cost — visible lines with the flag versus without, flipped in the config.
466
+ 3. Does it actually flake? Write COUNT does not predict the race; write TIMING relative to the end
467
+ of a file does. The starter's unit suite makes 114 writes and did not flake in 15 runs;
468
+ nest-server's makes 9 and flaked about 1 in 10.
469
+
470
+ Where a suite flakes AND the noise cost is high, the better fix is neither option: silence the
471
+ writes at the source. `nuxt-base-starter` measures 0 writes and 0 noise because its
472
+ `tests/unit/setup.ts` mocks `console.debug`/`console.info` globally.
473
+
474
+ ### Three things that made this expensive to diagnose
475
+
476
+ 1. **It is a race, not a late log.** Every spec involved `await`s correctly. Hunting for an
477
+ unawaited promise finds nothing and sends you the wrong way.
478
+ 2. **The reported file is not the cause.** vitest attributes the unhandled rejection to whichever
479
+ file's worker was running ("It doesn't mean the error was thrown inside the file itself").
480
+ The file it named logs nothing of its own.
481
+ 3. **A wrong explanation survives five green runs.** The first diagnosis here — a keep-alive
482
+ socket holding a handle — was plausible, fitted the observation, and was WRONG; a bisect with
483
+ the suspected file excluded still reproduced it. At ~1 in 10, a handful of green runs is not
484
+ evidence of anything. Bisect, or do not claim a cause.
485
+
486
+ ### Where the output actually came from
487
+
488
+ Worth recording, because `tests/setup.ts` looks like it already handles this and does not — and
489
+ because the obvious remedy is the wrong one.
490
+
491
+ **Only raw `console.*` calls feed the RPC. Nest `Logger` output does not.** vitest replaces
492
+ `globalThis.console` and nothing else; it does not patch `process.stdout`/`stderr`. Nest's
493
+ `ConsoleLogger` writes straight to those streams, so its output reaches the terminal without ever
494
+ becoming an `onUserConsoleLog` call. Verified both ways: a `[Nest] … DEBUG …` line carries no
495
+ `stdout | <file>` prefix, while every attributed line traces to a bare `console.*`.
496
+
497
+ The consequence is the useful part: **silencing the Nest logger does nothing for this flake.**
498
+ `Logger.overrideLogger(['error','fatal'])` — and any per-spec capture of `logger.error` — is noise
499
+ reduction, not a fix. Reaching for it because the loud lines look like the culprit is a dead end.
500
+
501
+ The writes that actually fed the RPC:
502
+
503
+ | Source | Call |
504
+ |--------|------|
505
+ | `common/helpers/config.helper.ts` | `console.info` — "Configured for: …", "No local config.json found!" |
506
+ | `common/services/config.service.ts` | `console.warn` from `mergeConfig` |
507
+ | `common/services/rate-limit-store.ts` | `console.warn` from `InMemoryRateLimitStore.hit` |
508
+ | `modules/hub/hub-buffer.ts` | `console.debug` from `readShared` |
509
+ | `modules/better-auth/…-email-verification.service.ts` | `console.log` from `logAuthUrlForDevelopment` |
510
+
511
+ ### Separately: capture the error output a spec EXPECTS
512
+
513
+ Independent of the flake, and still worth doing — `captureExpectedLogs()` in
514
+ `tests/helpers/expected-log-output.ts`. A spec that deliberately drives a failure path (SMTP down,
515
+ Redis refused, GridFS chunks missing) otherwise prints `logger.error` plus stack traces on a GREEN
516
+ run. That is the same "output that is always there is output nobody reads" argument the rest of
517
+ this file makes, and the helper RETURNS what was logged so the message becomes an assertion rather
518
+ than noise. Four specs use it; three gained a real assertion in the process, and one —
519
+ `'re-throws a send failure after logging it'` — had never asserted the half of its name after the
520
+ comma.
521
+
522
+ Do not reach for a global silence instead: `Logger.overrideLogger([])` would also silence the
523
+ failing run, removing the diagnostics you need exactly when something breaks.
524
+
373
525
  ## A catch that asserts nothing makes its test pass on every outcome
374
526
 
375
527
  **Rule: a `catch` block in a test either asserts something that could be false, or rethrows. Never
@@ -446,6 +598,33 @@ The vector predates 11.38.0 — Better-Auth already hashed on reset — so this
446
598
  factor roughly doubling, not a new exposure. It is not scaffolded here because a load profile
447
599
  belongs with a running API and an agreed traffic shape, not bolted onto a static review.
448
600
 
601
+ ## A test that reads `CI` answers differently on a runner
602
+
603
+ **Rule: when a spec drives behaviour that depends on the `CI` environment variable, it must PIN the
604
+ variable — never inherit it.** Otherwise the assertion means one thing on a laptop and another on a
605
+ runner, and the laptop is where it gets written.
606
+
607
+ `scripts/check-overrides.mjs` is the case: an unverified suppression is TOLERATED locally and
608
+ ESCALATED to a hard failure under `CI`, deliberately, because a skip nobody reads is
609
+ indistinguishable from a check that ran. `tests/unit/check-overrides.guard.spec.ts` spawns that
610
+ guard, so every case it runs inherits whatever `CI` the surrounding process has.
611
+
612
+ One case did not pin it, asserted `status === 0`, and passed locally for its whole life. It failed
613
+ the release CI run for 11.40.0 — the first time it had ever executed on a runner. The fix is one
614
+ line (`env: { CI: '' }`); the point is that nothing would have found it earlier, because the
615
+ environment that breaks it is the one nobody runs tests in by hand.
616
+
617
+ **Before a release, run the unit suite the way a runner sees it:**
618
+
619
+ ```bash
620
+ CI=true npx vitest run --config vitest.config.ts --reporter=dot
621
+ ```
622
+
623
+ Deliberately NOT wired into `check`. It would run all 2381 unit tests a second time — about 40s on
624
+ every local check — to protect against a class that currently has exactly one member, and CI itself
625
+ already catches it at the cost of one failed PR run. Revisit that trade if a second env-dependent
626
+ spec appears; the balance is about how many, not about principle.
627
+
449
628
  ## Consumer gate: the starter runs BEFORE publish, not after
450
629
 
451
630
  `pnpm run check:consumer` builds the tarball (`pnpm pack`), installs it into a **throwaway copy** of
package/CLAUDE.md CHANGED
@@ -24,7 +24,8 @@ The following documents must be kept up to date when making changes that affect
24
24
  | `.claude/rules/configurable-features.md` | Adding new configurable features |
25
25
  | `src/templates/*.ejs` + `tests/unit/email-templates.spec.ts` | Changing a mail template — a template is never imported, type-checked or linted, so the only thing binding it to its caller is the variable names inside it. Add the caller's data shape to the spec |
26
26
  | `FRAMEWORK-API.md` | Auto-regenerated by `pnpm run build` — verify after adding interfaces, CrudService methods, or core modules |
27
- | `.claude/rules/testing.md` | Changing the test-runner split, the per-run DB lifecycle or its **drop guard**, the run governor, the infrastructure containers, or the regression-evidence gate. This row exists because the drop guard the one thing standing between a test run and a developer's data went undocumented for its whole life: nothing in this table pointed at the file that describes everything around it |
27
+ | `.claude/rules/package-management.md` | Changing the `overrides:` set, adding or removing an `auditConfig.ignoreGhsas` suppression, or changing the `check:overrides` guard. Same reasoning as the row below: the guard exists because an override and a suppression both decay in silence and a guard nobody knows about decays exactly the same way |
28
+ | `.claude/rules/testing.md` | Changing the test-runner split, the per-run DB lifecycle or its **drop guard**, the run governor, the infrastructure containers, the regression-evidence gate, or **`disableConsoleIntercept`** (both runners set it; removing it to get per-file console attribution back re-arms an `EnvironmentTeardownError` that fails `check` roughly 1 run in 10 with every test green). This row exists because the drop guard — the one thing standing between a test run and a developer's data — went undocumented for its whole life: nothing in this table pointed at the file that describes everything around it |
28
29
 
29
30
  **Rule:** When a code change adds, removes, or modifies a feature listed in `docs/REQUEST-LIFECYCLE.md` (Features Overview, diagrams, decorator reference, configuration, etc.), update the document in the same commit or PR.
30
31
 
@@ -131,6 +132,17 @@ pnpm run lint:fix # Auto-fix
131
132
  pnpm run format # oxfmt format
132
133
 
133
134
  # Import-cycle / SWC safety (part of `check`)
135
+ # Supply-chain guards (part of `check`)
136
+ pnpm run check:overrides # Cross-checks every pnpm override and every auditConfig.ignoreGhsas
137
+ # suppression against live advisory data. The only step that catches an
138
+ # override whose target drifted BELOW the advisory's fixed-in version:
139
+ # `pnpm audit` reports the advisory, but nothing otherwise says that a
140
+ # supposed remedy for it is already sitting in pnpm-workspace.yaml.
141
+ # Also catches a suppression upstream has since patched — those are
142
+ # invisible to `pnpm audit` by design, so nothing else can.
143
+ # See .claude/rules/package-management.md → "Overrides AGE"
144
+ pnpm peers check # pnpm 11 builtin: unmet/missing peer dependencies, read from the lockfile
145
+
134
146
  pnpm run check:swc-tdz # SWC→CJS build, loads EVERY module as its own entry point.
135
147
  # The only step that catches a temporal-dead-zone crash from an
136
148
  # import cycle — tsc, vitest and oxlint are all blind to it.
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 on 2026-09-02 (v11.39.0)
3
+ > Auto-generated from source code as of 2026-09-04 (v11.40.0)
4
4
  > File: `FRAMEWORK-API.md` — compact, machine-readable API surface for Claude Code
5
5
 
6
6
  ## CoreModule.forRoot()
@@ -109,7 +109,7 @@ When `passkey` is enabled, `trustedOrigins` is required (compile-time enforcemen
109
109
 
110
110
  ### IAi
111
111
 
112
- - `allowedBaseUrlHosts?`: `string[] | undefined` — Optional SSRF allowlist for connection base URLs. When set (non-empty), the
112
+ - `allowedBaseUrlHosts?`: `string | string[] | undefined` — Optional SSRF allowlist for connection base URLs. When set (non-empty), the
113
113
  - `audit?`: `boolean | undefined` (default: `false`) — Persist an audit record (`aiInteractions`) for every prompt run (admin-readable).
114
114
  - `budget?`: `{ period?: "day" | "month" | "none"; tenant?: { maxPrompts?: number; maxToken...` — Token/prompt budgets for AI prompts, enforced before a run (HTTP 429 + translated
115
115
  - `capabilityDriftCheck?`: `boolean | undefined` (default: `false`) — Opt-in boot self-check: after startup, probe each enabled connection that declares
@@ -189,7 +189,7 @@ export interface IAiRateLimit {
189
189
  windowSeconds?: number;
190
190
  }
191
191
  export interface IAi {
192
- allowedBaseUrlHosts?: string[];
192
+ allowedBaseUrlHosts?: string | string[];
193
193
  audit?: boolean;
194
194
  budget?: {
195
195
  period?: 'day' | 'month' | 'none';
@@ -9,6 +9,8 @@ export declare class OpenAiCompatibleProvider implements ILlmProvider {
9
9
  constructor(connection: ResolvedAiConnection);
10
10
  chat(messages: LlmMessage[], tools: LlmToolSchema[], options?: LlmCompletionOptions): Promise<LlmResponse>;
11
11
  protected assertBaseUrlAllowed(url: string): void;
12
+ protected resolveAllowedBaseUrlHosts(): string[];
13
+ protected normaliseHostEntry(value: string): string;
12
14
  detectCapabilities(): Promise<{
13
15
  jsonResponse?: boolean;
14
16
  nativeTools?: boolean;
@@ -84,8 +84,8 @@ class OpenAiCompatibleProvider {
84
84
  };
85
85
  }
86
86
  assertBaseUrlAllowed(url) {
87
- const allowedHosts = config_service_1.ConfigService.get('ai.allowedBaseUrlHosts');
88
- if (!Array.isArray(allowedHosts) || !allowedHosts.length) {
87
+ const allowedHosts = this.resolveAllowedBaseUrlHosts();
88
+ if (!allowedHosts.length) {
89
89
  return;
90
90
  }
91
91
  let parsed;
@@ -95,11 +95,35 @@ class OpenAiCompatibleProvider {
95
95
  catch {
96
96
  throw new common_1.ServiceUnavailableException(error_code_1.ErrorCode.AI_CONNECTION_INVALID_URL);
97
97
  }
98
- if (!allowedHosts.includes(parsed.host) && !allowedHosts.includes(parsed.hostname)) {
98
+ const defaultPort = parsed.protocol === 'https:' ? '443' : parsed.protocol === 'http:' ? '80' : '';
99
+ const candidates = [parsed.host, parsed.hostname];
100
+ if (defaultPort && parsed.host === parsed.hostname) {
101
+ candidates.push(`${parsed.hostname}:${defaultPort}`);
102
+ }
103
+ if (!candidates.map((candidate) => this.normaliseHostEntry(candidate)).some((c) => allowedHosts.includes(c))) {
99
104
  this.logger.warn(`AI connection "${this.connection.name}" host "${parsed.host}" is not in ai.allowedBaseUrlHosts`);
100
105
  throw new common_1.ServiceUnavailableException(error_code_1.ErrorCode.AI_CONNECTION_NOT_AVAILABLE);
101
106
  }
102
107
  }
108
+ resolveAllowedBaseUrlHosts() {
109
+ const configured = config_service_1.ConfigService.get('ai.allowedBaseUrlHosts');
110
+ if (configured === undefined || configured === null) {
111
+ return [];
112
+ }
113
+ const entries = typeof configured === 'string' ? configured.split(',') : configured;
114
+ if (!Array.isArray(entries)) {
115
+ this.logger.error(`ai.allowedBaseUrlHosts is a ${typeof configured} and carries no hostnames — the SSRF egress ` +
116
+ 'allowlist is NOT active. Use an array or a comma-separated string.');
117
+ return [];
118
+ }
119
+ return entries.map((host) => this.normaliseHostEntry(String(host))).filter(Boolean);
120
+ }
121
+ normaliseHostEntry(value) {
122
+ return value
123
+ .trim()
124
+ .toLowerCase()
125
+ .replace(/\.(?=$|:)/, '');
126
+ }
103
127
  async detectCapabilities() {
104
128
  const result = {};
105
129
  if (this.connection.supportsJsonResponse === undefined) {
@@ -179,6 +203,7 @@ class OpenAiCompatibleProvider {
179
203
  if (!base.startsWith('http')) {
180
204
  return undefined;
181
205
  }
206
+ this.assertBaseUrlAllowed(`${base}/api/show`);
182
207
  const response = await fetch(`${base}/api/show`, {
183
208
  body: JSON.stringify({ name: this.connection.model }),
184
209
  headers: { 'Content-Type': 'application/json' },
@@ -1 +1 @@
1
- {"version":3,"file":"openai-compatible.provider.js","sourceRoot":"","sources":["../../../../../src/core/modules/ai/providers/openai-compatible.provider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"openai-compatible.provider.js","sourceRoot":"","sources":["../../../../../src/core/modules/ai/providers/openai-compatible.provider.ts"],"names":[],"mappings":";;;AAAA,2CAA0F;AAE1F,4EAAwE;AACxE,iDAA6C;AAwB7C,MAAa,wBAAwB;IAON;IANpB,YAAY,CAAkB;IAC9B,IAAI,GAAG,mBAAmB,CAAC;IAEnB,MAAM,GAAG,IAAI,eAAM,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC;IACnD,gBAAgB,CAAS;IAE1C,YAA6B,UAAgC;QAAhC,eAAU,GAAV,UAAU,CAAsB;QAC3D,IAAI,CAAC,YAAY,GAAG;YAClB,YAAY,EAAE,UAAU,CAAC,oBAAoB,IAAI,KAAK;YACtD,WAAW,EAAE,UAAU,CAAC,mBAAmB,IAAI,KAAK;YACpD,YAAY,EAAE,IAAI;SACnB,CAAC;QAEF,IAAI,CAAC,gBAAgB,GAAG,UAAU,CAAC,SAAS,IAAI,OAAO,CAAC;IAC1D,CAAC;IASD,KAAK,CAAC,IAAI,CAAC,QAAsB,EAAE,KAAsB,EAAE,OAA8B;QACvF,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,mBAAmB,CAAC;QAC7E,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,IAAI,CAAC,UAAU,CAAC,IAAI,2BAA2B,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7G,MAAM,IAAI,oCAA2B,CAAC,sBAAS,CAAC,yBAAyB,CAAC,CAAC;QAC7E,CAAC;QACD,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAE/B,MAAM,IAAI,GAAwB;YAChC,UAAU,EAAE,OAAO,EAAE,SAAS,IAAI,IAAI,CAAC,UAAU,CAAC,gBAAgB,IAAI,IAAI;YAC1E,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAG7B,OAAO,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;gBAClC,IAAI,EAAE,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;aAC1C,CAAC,CAAC;YACH,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK;YAC9C,MAAM,EAAE,KAAK;YACb,WAAW,EAAE,OAAO,EAAE,WAAW,IAAI,IAAI,CAAC,UAAU,CAAC,kBAAkB,IAAI,GAAG;SAC/E,CAAC;QAGF,IAAI,IAAI,CAAC,YAAY,CAAC,WAAW,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YAClD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC7B,QAAQ,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE;gBAChF,IAAI,EAAE,UAAU;aACjB,CAAC,CAAC,CAAC;QACN,CAAC;QACD,IAAI,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC;YACnC,IAAI,CAAC,eAAe,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;QACjD,CAAC;QAED,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,IAAI,CAAC,gBAAgB,CAAC;QAC9D,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAC1B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;gBAC1B,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE;oBACjD,cAAc,EAAE,kBAAkB;iBACnC;gBACD,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC;aACvC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAI,GAAa,EAAE,IAAI,KAAK,cAAc,CAAC,CAAC,CAAC,iBAAiB,SAAS,IAAI,CAAC,CAAC,CAAE,GAAa,CAAC,OAAO,CAAC;YAClH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,IAAI,CAAC,UAAU,CAAC,IAAI,aAAa,OAAO,EAAE,CAAC,CAAC;YAC/E,MAAM,IAAI,oCAA2B,CAAC,sBAAS,CAAC,iBAAiB,CAAC,CAAC;QACrE,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACnD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,QAAQ,CAAC,MAAM,QAAQ,GAAG,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YAC/F,MAAM,IAAI,4BAAmB,CAAC,sBAAS,CAAC,iBAAiB,CAAC,CAAC;QAC7D,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAGpC,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC;QAC5C,MAAM,IAAI,GAAG,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC;QACnC,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEhH,OAAO;YACL,GAAG,EAAE,MAAM;YACX,IAAI;YACJ,SAAS,EAAE,eAAe;YAC1B,KAAK,EAAE;gBACL,gBAAgB,EAAE,MAAM,CAAC,KAAK,EAAE,iBAAiB;gBACjD,YAAY,EAAE,MAAM,CAAC,KAAK,EAAE,aAAa;gBACzC,WAAW,EAAE,MAAM,CAAC,KAAK,EAAE,YAAY;aACxC;SACF,CAAC;IACJ,CAAC;IASS,oBAAoB,CAAC,GAAW;QACxC,MAAM,YAAY,GAAG,IAAI,CAAC,0BAA0B,EAAE,CAAC;QACvD,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;YACzB,OAAO;QACT,CAAC;QACD,IAAI,MAAW,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,oCAA2B,CAAC,sBAAS,CAAC,yBAAyB,CAAC,CAAC;QAC7E,CAAC;QAMD,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACnG,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,WAAW,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,QAAQ,EAAE,CAAC;YACnD,UAAU,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,IAAI,WAAW,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7G,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,kBAAkB,IAAI,CAAC,UAAU,CAAC,IAAI,WAAW,MAAM,CAAC,IAAI,oCAAoC,CACjG,CAAC;YACF,MAAM,IAAI,oCAA2B,CAAC,sBAAS,CAAC,2BAA2B,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IA2BS,0BAA0B;QAClC,MAAM,UAAU,GAAG,8BAAa,CAAC,GAAG,CAAU,wBAAwB,CAAC,CAAC;QACxE,IAAI,UAAU,KAAK,SAAS,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACpD,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;QACpF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,+BAA+B,OAAO,UAAU,8CAA8C;gBAC5F,oEAAoE,CACvE,CAAC;YACF,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACtF,CAAC;IAUS,kBAAkB,CAAC,KAAa;QACxC,OAAO,KAAK;aACT,IAAI,EAAE;aACN,WAAW,EAAE;aACb,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAC9B,CAAC;IAaD,KAAK,CAAC,kBAAkB;QACtB,MAAM,MAAM,GAAsD,EAAE,CAAC;QACrE,IAAI,IAAI,CAAC,UAAU,CAAC,oBAAoB,KAAK,SAAS,EAAE,CAAC;YACvD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC;gBAC3B,UAAU,EAAE,CAAC;gBACb,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,yCAAyC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gBAChF,eAAe,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE;aACzC,CAAC,CAAC;YACH,MAAM,CAAC,YAAY,GAAG,GAAG,CAAC,EAAE,CAAC;QAC/B,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,CAAC,mBAAmB,KAAK,SAAS,EAAE,CAAC;YACtD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC;gBAC3B,UAAU,EAAE,CAAC;gBACb,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,qBAAqB,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gBAC5D,WAAW,EAAE,UAAU;gBACvB,KAAK,EAAE;oBACL;wBACE,QAAQ,EAAE;4BACR,WAAW,EAAE,2BAA2B;4BACxC,IAAI,EAAE,MAAM;4BACZ,UAAU,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;yBAC/C;wBACD,IAAI,EAAE,UAAU;qBACjB;iBACF;aACF,CAAC,CAAC;YACH,MAAM,CAAC,WAAW,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC;QACvF,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAMS,KAAK,CAAC,KAAK,CAAC,KAA0B;QAC9C,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,mBAAmB,CAAC;QAC7E,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,oCAA2B,CAAC,sBAAS,CAAC,yBAAyB,CAAC,CAAC;QAC7E,CAAC;QACD,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC;YAChE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAClG,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,IAAI,MAAM,CAAC;SACjE,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;QACvB,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC1D,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IAOD,KAAK,CAAC,mBAAmB;QACvB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC3E,OAAO,WAAW,IAAI,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACvE,CAAC;IAMS,kBAAkB,CAAC,KAAyB;QACpD,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QACtC,MAAM,KAAK,GAAyB;YAClC,CAAC,SAAS,EAAE,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;YACvC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC;YACrB;gBACE,OAAO;gBACP,CAAC,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,CAAC;aAC5G;YACD,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;YACjF,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC;YACrB,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;YACnD,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC;YACrB,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;SACxC,CAAC;QACF,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpC,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAMS,KAAK,CAAC,kBAAkB;QAChC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAChF,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7B,OAAO,SAAS,CAAC;QACnB,CAAC;QAOD,IAAI,CAAC,oBAAoB,CAAC,GAAG,IAAI,WAAW,CAAC,CAAC;QAC9C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,WAAW,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YACrD,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,IAAI,MAAM,CAAC;SACjE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC1B,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC;YAClB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAyD,CAAC;QACpH,MAAM,IAAI,GAAG,IAAI,EAAE,UAAU,CAAC;QAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC;QACzE,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IACpE,CAAC;IAYS,iBAAiB,CAAC,CAA2C;QACrE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;YAC3D,OAAO,CAAC,CAAC,OAAO,CAAC;QACnB,CAAC;QACD,MAAM,KAAK,GAAU,EAAE,CAAC;QACxB,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;YACd,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAChD,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,OAAO,CAAC;YACjC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,SAAS;YACX,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QACxD,CAAC;QACD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC1C,CAAC;IAES,kBAAkB,CAAC,SAA4B;QACvD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,SAAS;aACb,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC;aAChC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,IAAI,UAAU,GAAwB,EAAE,CAAC;YACzC,IAAI,CAAC;gBACH,UAAU,GAAG,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5E,CAAC;YAAC,MAAM,CAAC;gBACP,UAAU,GAAG,EAAE,CAAC;YAClB,CAAC;YACD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACpE,CAAC,CAAC,CAAC;IACP,CAAC;CACF;AAtXD,4DAsXC"}