Lifecycle leftovers (0.20.0)
Daloy 0.20.0 closes four leftover lifecycle items of the secure-by-default initiative. Each one is additive and opt-in (or, in the case of disconnectStatusCode, only changes the status code recorded for already-aborted requests):
loadShedding()— first-party event-loop pressure monitor that returns503 Service Unavailable+Retry-Afterwhen the process is overloaded.app.cspReportRoute()— rate-limited POST receiver for CSP violation reports, plussecureHeaders({ reportingEndpoints, reportTo })wiring so a single line registers the endpoint and threads it back into the CSP header.disconnectStatusCode: 499default — client-aborted requests record499instead of a5xx, so dashboards separate scraper aborts from real server failures.defineConfig({ schema, source })— boot-time typed configuration validation through a Standard Schema (Zod / Valibot / ArkType / TypeBox), with aggregated error reporting.
1. loadShedding()
Drop-in middleware that samples event-loop delay, event-loop utilization, heap, and RSS through node:perf_hooks. When any configured threshold is breached, every incoming request is short-circuited with a structured 503 problem+json carrying Retry-After. The sampler is unref()'d so it never pins the event loop, and the whole module is a silent no-op on runtimes without node:perf_hooks (Cloudflare Workers, Vercel Edge, Fastly Compute) so the same line is portable.
Defaults are off for the deployment-specific thresholds (heap, RSS) and conservative for everything else; tighten them once you have real baselines from production.
2. app.cspReportRoute() + secureHeaders reporting wiring
Registers a rate-limited POST receiver for browser CSP violation reports. Defaults: path /__csp-report, per-IP rate limit 60 requests / 60s, body cap 8 KiB (hard-capped at 64 KiB since 0.30.0), accepted content types application/csp-report and application/reports+json. application/json is refused with 415.
Bad content-types receive 415, oversize payloads 413, malformed JSON 400, and rate-limited callers 429. The default logger sink omits the parsed report body in production unless logCspReportBodies: true is set explicitly; CSP reports include violated URLs, and URLs are where PII likes to hide when nobody is looking. Sink errors are caught and logged at error through the pluggable redacted logger without breaking the 204 response.
3. disconnectStatusCode: 499 default
When the client closes the connection before the response completes (the request AbortSignal fires), the dispatcher logs { event: "request.disconnected", status: 499 } and returns an empty 499 response. Access-log dashboards and SLO alerts then cleanly separate client aborts (scrapers, aborted fetches, WAF-blocked retries) from real 5xx failures.
Cannot be silenced to a 2xx or escalated to a 5xx — the value is pinned to the [400, 499] range (or 0 to keep whatever status the handler produced).
4. defineConfig({ schema, source })
Boot-time helper that validates the app's runtime configuration through a Standard Schema (Zod / Valibot / ArkType / TypeBox). Closes the "we shipped to production with JWT_SECRET=undefinedbecause the env var wasn't set on the new cluster" class of bugs at the framework boundary — not at every middleware that consumes the secret.
defineConfig reports every offending key in one pass (not just the first one) so a cold-start deploy fixes a misconfigured cluster on the first try. Suppress the stderr summary with { stderr: false } if you want to handle the error structurally yourself.