@daloyjs/core 1.0.0-beta.4 → 1.0.0-beta.6

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/README.md CHANGED
@@ -36,7 +36,7 @@ Most backend code is now written with AI. Non-developers describe an app and shi
36
36
 
37
37
  DaloyJS is built for exactly this moment, from two directions at once:
38
38
 
39
- - **A secure-by-default runtime.** Body limits, prototype-pollution-safe JSON, path-traversal rejection, request timeouts, header-injection guards, real `405`s, and RFC 9457 problem+json with prod-mode redaction are on in the constructor — the dangerous things are off when nobody remembered to turn them off. The app also *refuses to boot* on unsafe configuration (wildcard CORS with credentials, weak session secrets, a state-changing session route with no CSRF protection, unconfigured `X-Forwarded-*` in production).
39
+ - **A secure-by-default runtime.** Body limits, prototype-pollution-safe JSON, path-traversal rejection, request timeouts, header-injection guards, real `405`s, and RFC 9457 problem+json with prod-mode redaction are on in the constructor — the dangerous things are off when nobody remembered to turn them off. The app also _refuses to boot_ on unsafe configuration (wildcard CORS with credentials, weak session secrets, a state-changing session route with no CSRF protection, unconfigured `X-Forwarded-*` in production).
40
40
  - **A hardened supply chain.** `@daloyjs/core` ships **zero runtime dependencies**, is published with npm provenance and CycloneDX + SPDX SBOMs, and the pnpm posture (`ignore-scripts`, a 24-hour release-age cooldown, source-verified lockfiles) plus the CI `verify:*` gates shrink the blast radius of the campaigns making headlines.
41
41
 
42
42
  The point is that none of this costs you developer experience or portability: you keep contract-first DX in the league of ts-rest, Elysia, and FastAPI, and Hono-grade portability across Node, Bun, Deno, Workers, Vercel, Fastly, and Lambda. The secure path is simply the path of least resistance. See [Vibe Coding Security: what DaloyJS already blocks](https://daloyjs.dev/blog/vibe-coding-security-what-daloyjs-already-blocks) and the [security docs](https://daloyjs.dev/docs/security).
@@ -45,19 +45,19 @@ The point is that none of this costs you developer experience or portability: yo
45
45
 
46
46
  DaloyJS exists to be the framework you'd build if you took the best ideas from each modern stack:
47
47
 
48
- | You want | Today's best-of | What DaloyJS gives you |
49
- | ------------------------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
50
- | Best **OpenAPI ergonomics** | [FastAPI](https://fastapi.tiangolo.com) | OpenAPI 3.1 from a single route definition; `docs: true` mounts `/docs` and `/openapi.json`. |
51
- | Best **Vercel / serverless / edge fit** | [Hono](https://hono.dev/docs/) | Web-standard `Request → Response` core with adapters for Node, Bun, Deno, Cloudflare, Vercel, Fastly, and Lambda. |
52
- | Mature **Swagger / docs / ops** in Node | [Fastify](https://fastify.dev/docs/latest/Reference/) | Encapsulated plugins, structured logger, graceful shutdown, request ids, and lifecycle hooks — all first-party. |
53
- | Modern **TS-first DX**, Bun acceptable | [Elysia](https://elysiajs.com/at-glance.html) | End-to-end typed handlers, typed context, and a typed in-process client — no codegen step required. |
54
- | Best-in-class **typed client codegen** for any consumer | [Hey API](https://heyapi.dev/openapi-ts/get-started) | One `pnpm gen` command emits a fully-typed fetch SDK from your live OpenAPI spec. |
55
- | **Contract-first typed client, no codegen** | [ts-rest](https://ts-rest.com/) | Your route definition *is* the contract: an in-process typed client with zero codegen, plus OpenAPI 3.1 + a Hey API SDK for consumers that can't import your types. |
56
- | Opinionated **DI / module architecture** for large teams | [NestJS](https://docs.nestjs.com/) | Plugin encapsulation, `register()` prefixes, and `defineDependency()` typed-DI with per-request dedup — no decorators. |
57
- | Minimalist **async middleware cascade** | [Koa](https://koajs.com/) | Koa-style `Context` on a web-standard core, with validation, OpenAPI, errors, and security headers in-box. |
58
- | **Services + real-time** API framework | [FeathersJS](https://feathersjs.com/) | First-party `app.ws()` with CSWSH refuse-to-boot guards, plus SSE / NDJSON streaming and raw `Response` passthrough (return a Vercel AI SDK stream straight from a handler) over explicit OpenAPI routes. |
59
- | Battle-tested **Node middleware compatibility** | [Express v5](https://expressjs.com/en/blog/2024-10-15-v5-release) | Regex-free trie router, schema-validated routes, RFC 9457 problem+json, and refuse-to-boot guards on every runtime. |
60
- | **Portable supply-chain hardening** for the apps you build | [pnpm](https://pnpm.io/motivation) defaults + a zero-runtime-dep core | Hardened `.npmrc`, source-verified lockfiles, zero runtime deps, CycloneDX + SPDX SBOM, and npm provenance attestations. |
48
+ | You want | Today's best-of | What DaloyJS gives you |
49
+ | ---------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
50
+ | Best **OpenAPI ergonomics** | [FastAPI](https://fastapi.tiangolo.com) | OpenAPI 3.1 from a single route definition; `docs: true` mounts `/docs` and `/openapi.json`. |
51
+ | Best **Vercel / serverless / edge fit** | [Hono](https://hono.dev/docs/) | Web-standard `Request → Response` core with adapters for Node, Bun, Deno, Cloudflare, Vercel, Fastly, and Lambda. |
52
+ | Mature **Swagger / docs / ops** in Node | [Fastify](https://fastify.dev/docs/latest/Reference/) | Encapsulated plugins, structured logger, graceful shutdown, request ids, and lifecycle hooks — all first-party. |
53
+ | Modern **TS-first DX**, Bun acceptable | [Elysia](https://elysiajs.com/at-glance.html) | End-to-end typed handlers, typed context, and a typed in-process client — no codegen step required. |
54
+ | Best-in-class **typed client codegen** for any consumer | [Hey API](https://heyapi.dev/openapi-ts/get-started) | One `pnpm gen` command emits a fully-typed fetch SDK from your live OpenAPI spec. |
55
+ | **Contract-first typed client, no codegen** | [ts-rest](https://ts-rest.com/) | Your route definition _is_ the contract: an in-process typed client with zero codegen, plus OpenAPI 3.1 + a Hey API SDK for consumers that can't import your types. |
56
+ | Opinionated **DI / module architecture** for large teams | [NestJS](https://docs.nestjs.com/) | Plugin encapsulation, `register()` prefixes, and `defineDependency()` typed-DI with per-request dedup — no decorators. |
57
+ | Minimalist **async middleware cascade** | [Koa](https://koajs.com/) | Koa-style `Context` on a web-standard core, with validation, OpenAPI, errors, and security headers in-box. |
58
+ | **Services + real-time** API framework | [FeathersJS](https://feathersjs.com/) | First-party `app.ws()` with CSWSH refuse-to-boot guards, plus SSE / NDJSON streaming and raw `Response` passthrough (return a Vercel AI SDK stream straight from a handler) over explicit OpenAPI routes. |
59
+ | Battle-tested **Node middleware compatibility** | [Express v5](https://expressjs.com/en/blog/2024-10-15-v5-release) | Regex-free trie router, schema-validated routes, RFC 9457 problem+json, and refuse-to-boot guards on every runtime. |
60
+ | **Portable supply-chain hardening** for the apps you build | [pnpm](https://pnpm.io/motivation) defaults + a zero-runtime-dep core | Hardened `.npmrc`, source-verified lockfiles, zero runtime deps, CycloneDX + SPDX SBOM, and npm provenance attestations. |
61
61
 
62
62
  ```
63
63
  framework test suite passing · ≥90% line + function coverage / ≥90% branch coverage · typechecks on TypeScript 6 with `strict: true`
@@ -164,13 +164,7 @@ For maintainers, the safe rule is: use one publish path per version. Either publ
164
164
 
165
165
  ```ts
166
166
  import { z } from "zod";
167
- import {
168
- App,
169
- NotFoundError,
170
- secureHeaders,
171
- rateLimit,
172
- requestId,
173
- } from "@daloyjs/core";
167
+ import { App, NotFoundError, secureHeaders, rateLimit, requestId } from "@daloyjs/core";
174
168
  import { serve } from "@daloyjs/core/node";
175
169
 
176
170
  const app = new App({ bodyLimitBytes: 1024 * 1024, requestTimeoutMs: 5_000 });
@@ -282,6 +276,11 @@ new App({
282
276
  docExpansion: "none",
283
277
  displayRequestDuration: true,
284
278
  },
279
+ auth: {
280
+ loginUrl: "/login", // or Auth0 / Entra ID / Okta / Clerk / Better Auth
281
+ label: "Sign in",
282
+ target: "popup",
283
+ },
285
284
  tags: ["Docs"],
286
285
  },
287
286
  });
@@ -311,6 +310,9 @@ HTML helper. The `swagger` option is forwarded to `SwaggerUIBundle` with Daloy
311
310
  owning `url` / `dom_id`. Redoc spins up a `blob:` Web Worker for search, so the
312
311
  auto-mounted `/docs` page widens its CSP with `worker-src 'self' blob:` for
313
312
  `ui: "redoc"` only — Scalar and Swagger UI keep the tighter default.
313
+ Add `docs.auth` when you want all three docs UIs to expose the same visible
314
+ authorization launcher; point it at a local login route or any OAuth2/OIDC
315
+ provider entry point.
314
316
 
315
317
  Prefer to mount manually? Import the helpers directly:
316
318
 
@@ -354,26 +356,26 @@ path is used. Others are first-party middleware so applications can choose the
354
356
  right CORS policy, rate-limit key, CSP, session secret, or CSRF rollout for their
355
357
  deployment.
356
358
 
357
- | Threat | Built-in behavior |
358
- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
359
- | **Body-size DoS** | Core-enforced streamed read with a hard cap (default 1 MiB); `Content-Length` checked first. |
360
- | **Prototype pollution** | Core JSON parser strips `__proto__` / `constructor` / `prototype` via reviver. |
361
- | **Header / response splitting** | Core header sanitizers reject CRLF + NUL. |
362
- | **Path traversal** | Core router rejects `..` segments and `//` before walking. |
363
- | **Slow-loris / hung handlers** | Core `requestTimeoutMs` aborts handlers (default 30 s); Node adapter sets `requestTimeout` + `headersTimeout` + `maxHeaderSize`. |
364
- | **HTTP/2 Bomb / header-count flood** | Core `maxHeaderCount` rejects requests with more than 100 header fields (`431`) before routing; Node adapter sets `server.maxHeadersCount`. See [SECURITY.md](SECURITY.md) for the upstream HTTP/2 mitigations. |
365
- | **MIME sniffing** | First-party `secureHeaders()` sets `X-Content-Type-Options: nosniff`; scaffolded apps enable it. |
366
- | **Clickjacking** | First-party `secureHeaders()` sets `X-Frame-Options: DENY` + CSP `frame-ancestors 'none'`; scaffolded apps enable it. |
367
- | **XSS via injected scripts** | First-party `secureHeaders()` provides a strict CSP `default-src 'self'` baseline; the directives-object form supports per-request **nonces** and **Trusted Types** (`require-trusted-types-for 'script'`). |
368
- | **Cross-origin leakage** | First-party `secureHeaders()` sets `cross-origin-opener-policy` + `cross-origin-resource-policy` to `same-origin`; scaffolded apps enable it. |
369
- | **CSRF** | First-party `csrf()` ships two strategies: **double-submit cookie** (default) and **Fetch-Metadata** (`Sec-Fetch-Site`-based, tokenless); both with timing-safe verification. |
370
- | **Information disclosure (5xx)** | Production mode strips `detail` from 5xx problem+json automatically. |
371
- | **Credential timing attacks** | First-party `timingSafeEqual()` helper for tokens & signatures. |
372
- | **Brute-force / scraping** | First-party `rateLimit()` with token-bucket + `Retry-After`; Node/Bun/Deno scaffolded apps enable it. |
373
- | **Method confusion** | Real **405** with `Allow` header, not a misleading 404. |
374
- | **CORS misconfig** | First-party `cors()` requires an explicit allowlist and throws for `*` with credentials. |
375
- | **Request correlation** | First-party `requestId()` uses cryptographic ids; scaffolded apps enable it. |
376
- | **Supply chain (portable)** | pnpm scaffolds keep `ignore-scripts=true`, `minimum-release-age=1440`, verified store, reproducible lockfile, and `pnpm verify:lockfile` source verification; every app also installs a zero-runtime-dependency `@daloyjs/core` published with CycloneDX + SPDX SBOM and npm provenance you can verify on install — regardless of where you host your repo. |
359
+ | Threat | Built-in behavior |
360
+ | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
361
+ | **Body-size DoS** | Core-enforced streamed read with a hard cap (default 1 MiB); `Content-Length` checked first. |
362
+ | **Prototype pollution** | Core JSON parser strips `__proto__` / `constructor` / `prototype` via reviver. |
363
+ | **Header / response splitting** | Core header sanitizers reject CRLF + NUL. |
364
+ | **Path traversal** | Core router rejects `..` segments and `//` before walking. |
365
+ | **Slow-loris / hung handlers** | Core `requestTimeoutMs` aborts handlers (default 30 s); Node adapter sets `requestTimeout` + `headersTimeout` + `maxHeaderSize`. |
366
+ | **HTTP/2 Bomb / header-count flood** | Core `maxHeaderCount` rejects requests with more than 100 header fields (`431`) before routing; Node adapter sets `server.maxHeadersCount`. See [SECURITY.md](SECURITY.md) for the upstream HTTP/2 mitigations. |
367
+ | **MIME sniffing** | First-party `secureHeaders()` sets `X-Content-Type-Options: nosniff`; scaffolded apps enable it. |
368
+ | **Clickjacking** | First-party `secureHeaders()` sets `X-Frame-Options: DENY` + CSP `frame-ancestors 'none'`; scaffolded apps enable it. |
369
+ | **XSS via injected scripts** | First-party `secureHeaders()` provides a strict CSP `default-src 'self'` baseline; the directives-object form supports per-request **nonces** and **Trusted Types** (`require-trusted-types-for 'script'`). |
370
+ | **Cross-origin leakage** | First-party `secureHeaders()` sets `cross-origin-opener-policy` + `cross-origin-resource-policy` to `same-origin`; scaffolded apps enable it. |
371
+ | **CSRF** | First-party `csrf()` ships two strategies: **double-submit cookie** (default) and **Fetch-Metadata** (`Sec-Fetch-Site`-based, tokenless); both with timing-safe verification. |
372
+ | **Information disclosure (5xx)** | Production mode strips `detail` from 5xx problem+json automatically. |
373
+ | **Credential timing attacks** | First-party `timingSafeEqual()` helper for tokens & signatures. |
374
+ | **Brute-force / scraping** | First-party `rateLimit()` with token-bucket + `Retry-After`; Node/Bun/Deno scaffolded apps enable it. |
375
+ | **Method confusion** | Real **405** with `Allow` header, not a misleading 404. |
376
+ | **CORS misconfig** | First-party `cors()` requires an explicit allowlist and throws for `*` with credentials. |
377
+ | **Request correlation** | First-party `requestId()` uses cryptographic ids; scaffolded apps enable it. |
378
+ | **Supply chain (portable)** | pnpm scaffolds keep `ignore-scripts=true`, `minimum-release-age=1440`, verified store, reproducible lockfile, and `pnpm verify:lockfile` source verification; every app also installs a zero-runtime-dependency `@daloyjs/core` published with CycloneDX + SPDX SBOM and npm provenance you can verify on install — regardless of where you host your repo. |
377
379
 
378
380
  **Portable vs. GitHub-only.** The runtime protections and the published `@daloyjs/core` SBOM/provenance travel with every app you scaffold, no matter which CI host you use — GitLab, Bitbucket, Azure DevOps, Jenkins, on-prem, or laptop. The strongest install-time bundle is available when you choose pnpm, because `minimum-release-age`, `blockExoticSubdeps`, and the workspace gates are pnpm features. The **`@daloyjs/core` release pipeline itself** is separately hardened on GitHub Actions — no `pull_request_target`, no Actions cache, top-level `permissions: {}`, `step-security/harden-runner`, a protected `release.yml`, npm trusted publishing with `--provenance`, CodeQL + Opengrep dual SAST, OpenSSF Scorecard, zizmor, Dependabot, and CODEOWNERS — and `create-daloy --with-ci` ships the app-safe parts as an **optional GitHub Actions bundle** for teams on GitHub. See [SECURITY.md](SECURITY.md) and the [supply-chain security docs](https://daloyjs.dev/docs/security/supply-chain).
379
381
 
@@ -383,7 +385,7 @@ deployment.
383
385
 
384
386
  DaloyJS is a **resource server** (and a toolkit for building a relying party),
385
387
  **not** an identity provider. Like Hono, Express, Fastify, or ASP.NET Core, it
386
- *verifies* and *enforces* tokens on each request — it does **not** ship a login
388
+ _verifies_ and _enforces_ tokens on each request — it does **not** ship a login
387
389
  UI, a user database, or an OAuth2 authorization server. It is **not** an
388
390
  "IdentityServer": it cannot, on its own, do what Duende IdentityServer,
389
391
  Keycloak, or Auth0 do (run login pages, manage clients/consent, mint tokens).
@@ -425,7 +427,7 @@ miss 4,763,878 ops/sec
425
427
  For deployments where every millisecond of startup matters (Lambda, Vercel, Cloudflare Workers, Fastly Compute), import `App` from the deep entry point instead of the barrel:
426
428
 
427
429
  ```ts
428
- import { App } from "@daloyjs/core/app"; // ~13 ms faster cold start than "@daloyjs/core"
430
+ import { App } from "@daloyjs/core/app"; // ~13 ms faster cold start than "@daloyjs/core"
429
431
  import { serve } from "@daloyjs/core/node";
430
432
  ```
431
433
 
@@ -507,17 +509,18 @@ The core only ever sees `Request → Response`. Adapters live at the edge.
507
509
 
508
510
  ## Status
509
511
 
510
- DaloyJS is now in the **`1.0.0` beta** (`1.0.0-beta.4`). The public API is feature-complete and stable for the 1.0 line; from `1.0.0` onward, breaking changes follow SemVer and deprecations get at least one minor cycle. Small adjustments are still possible before the `1.0.0` GA if beta feedback surfaces something. The framework is already in use for production trials.
512
+ DaloyJS is now in the **`1.0.0` beta** (`1.0.0-beta.6`). The public API is feature-complete and stable for the 1.0 line; from `1.0.0` onward, breaking changes follow SemVer and deprecations get at least one minor cycle. Small adjustments are still possible before the `1.0.0` GA if beta feedback surfaces something. The framework is already in use for production trials.
511
513
 
512
514
  **Release quality bar.** Every release ships with **≥90% line + function coverage and ≥90% branch coverage**, strict TypeScript, OpenSSF Scorecard, CodeQL + Opengrep dual SAST, zizmor workflow linting, and npm provenance. Coverage was relaxed from a former 100% gate so complex security work isn't blocked chasing throwaway tests for unreachable defensive branches or tsx source-map phantoms; see [AGENTS.md](AGENTS.md) for the policy.
513
515
 
514
516
  ### Routing, validation, and docs
515
517
 
516
518
  - Contract-first routing with Standard Schema validation (Zod 4, Valibot, ArkType, TypeBox) and OpenAPI 3.1 generated from a single source of truth.
517
- - Live OpenAPI 3.1 spec served as both JSON (`GET /openapi.json`) and YAML (`GET /openapi.yaml`) when `docs: true`, with a choice of Scalar (default), Swagger UI, or Redoc via `docs.ui`, plus Scalar theming/custom CSS/auth defaults via `docs.scalar`, Swagger UI options via `docs.swagger` (including persisted Authorize credentials), and Redoc options via `docs.redoc`.
519
+ - Live OpenAPI 3.1 spec served as both JSON (`GET /openapi.json`) and YAML (`GET /openapi.yaml`) when `docs: true`, with a choice of Scalar (default), Swagger UI, or Redoc via `docs.ui`, plus Scalar theming/custom CSS/auth defaults via `docs.scalar`, Swagger UI options via `docs.swagger` (including persisted Authorize credentials), Redoc options via `docs.redoc`, and a provider-neutral `docs.auth` launcher for local login routes or third-party OAuth2/OIDC providers.
518
520
  - Zero-config OpenAPI `info` autofill from `package.json` (Node / Bun) or `deno.json` / `deno.jsonc` (Deno); explicit `openapi.info` values always win.
519
521
  - RFC 7231 + RFC 5789 HTTP-method allowlist enforced inside `app.route()` (WebDAV, `TRACE`, `CONNECT` rejected at the framework boundary).
520
522
  - AI-friendly route metadata via optional `meta: { examples, extensions, summary, description, tags }`; examples are validated against your schemas at build time, surfaced as OpenAPI `examples` + `x-daloy-*` extensions, and dumped as `routes.json` / `routes.yaml` via `daloy inspect --ai`.
523
+ - Dependency-free MCP Streamable HTTP server helpers at `@daloyjs/core/mcp`: `createMcpHandler()` exposes tools, resources, and prompts over JSON-RPC 2.0, while `mcpRoutes("/mcp", handler)` mounts the POST / GET / OPTIONS Daloy routes for a dedicated MCP service with the same auth, rate-limit, body-limit, and timeout middleware as any other app.
521
524
  - API lifecycle and breaking-change detection: mark routes `deprecated` or give them a `sunset` date to emit RFC 8594 `Deprecation` / `Sunset` headers and an `x-sunset` OpenAPI extension, then gate CI with `diffOpenAPI()` / the `daloy diff` command, which fail on a breaking change versus the last published spec.
522
525
  - In-process test client (`app.request()`), contract-test runner (gated in CI via `daloy inspect --check` and shipped as a default test in every `create-daloy` template), in-process typed client, and Hey API codegen via `pnpm gen`.
523
526
 
@@ -608,6 +611,7 @@ The framework refuses to start (or to construct) when configuration is unsafe:
608
611
  - an Origin policy (`allowedOrigins: "same-origin"` / `string[]` / predicate) or `acknowledgeCrossOriginUpgrade: true`.
609
612
 
610
613
  This closes the Cross-Site WebSocket Hijacking (CSWSH) class of bug — Storybook's [CVE-2026-27148](https://www.aikido.dev/blog/storybooks-websockets-attack) is the representative case: cookie auth alone does not stop a malicious site from opening an authenticated WS handshake from a victim's browser. The Origin check runs **before** `beforeUpgrade` in both adapters.
614
+
611
615
  - Contract-first **AsyncAPI 3.0** generation for `app.ws()` surfaces via `@daloyjs/core/asyncapi` (`generateAsyncAPI()` / `asyncapiToYAML()`) and `daloy inspect --asyncapi`. Each route becomes a channel (address + path params) with a `receive` operation for inbound client messages and an optional `send` operation for outbound messages, described via an optional handler `meta` block (`summary` / `description` / `tags` / `send` / `receive` / `operationId`). Set `asyncapi: true` (mirroring `docs: true`) to **auto-mount an interactive AsyncAPI UI** at `/asyncapi` plus `/asyncapi.json` + `/asyncapi.yaml` — the WebSocket counterpart to the Scalar / Swagger / Redoc OpenAPI viewers, served from a CDN with the same SRI + strict-CSP hardening.
612
616
 
613
617
  ### Lifecycle and ops
@@ -663,7 +667,7 @@ DaloyJS is **public and MIT-licensed, but contributions-closed**. Pull requests
663
667
  from accounts that are not invited maintainers or explicit repository
664
668
  collaborators are closed automatically. Bug reports, feature requests, and
665
669
  security disclosures are very welcome; see [CONTRIBUTING.md](./CONTRIBUTING.md)
666
- and [SECURITY.md](./SECURITY.md) for the channels that *are* open.
670
+ and [SECURITY.md](./SECURITY.md) for the channels that _are_ open.
667
671
 
668
672
  ## License
669
673
 
package/dist/app.d.ts CHANGED
@@ -2,7 +2,7 @@ import { WebSocketRegistry, type WebSocketHandler } from "./websocket.js";
2
2
  import { type Logger } from "./logger.js";
3
3
  import type { HttpMethod, Hooks, PathString, RequestSchemas, ResponsesMap, RouteDefinition } from "./types.js";
4
4
  import { type OpenAPIInfo, type OpenAPIOptions } from "./openapi.js";
5
- import { type DocsAssetOptions, type DocsContentSecurityPolicyOptions, type RedocConfiguration, type ScalarJsonValue, type ScalarReferenceConfiguration, type SwaggerUiConfiguration } from "./docs.js";
5
+ import { type DocsAssetOptions, type DocsAuthLauncherOptions, type DocsContentSecurityPolicyOptions, type RedocConfiguration, type ScalarJsonValue, type ScalarReferenceConfiguration, type SwaggerUiConfiguration } from "./docs.js";
6
6
  import { type AsyncAPIServer } from "./asyncapi.js";
7
7
  import { type SecureHeadersOptions } from "./middleware.js";
8
8
  import { type LoadSheddingOptions } from "./load-shedding.js";
@@ -130,8 +130,8 @@ export interface AppOptions {
130
130
  /**
131
131
  * Master switch for the secure-by-default surface (auto-applied
132
132
  * {@link secureHeaders}, cross-origin guard for state-changing requests
133
- * when no {@link cors} hook allows the request origin). Defaults to `true`
134
- * in `@daloyjs/core@0.16.0` and later. Per-feature opt-outs
133
+ * when no {@link cors} hook allows the request origin). Defaults to `true`
134
+ * in `@daloyjs/core@0.16.0` and later. Per-feature opt-outs
135
135
  * (`secureHeaders: false`, `corsCrossOriginGuard: false`) remain available
136
136
  * when this is left on. Pass `false` to restore the pre-0.16 behavior
137
137
  * wholesale.
@@ -168,13 +168,13 @@ export interface AppOptions {
168
168
  secureHeaders?: SecureHeadersOptions | false;
169
169
  /**
170
170
  * Reject state-changing requests (`POST`, `PUT`, `PATCH`, `DELETE`) that
171
- * carry a cross-origin `Origin` header when no {@link cors} hook in the
172
- * matched route's hook chain allows that origin. Active when
173
- * {@link AppOptions.secureDefaults} is not `false`. Returns
174
- * `403 application/problem+json` so the rejection is loud at the network
175
- * boundary instead of silently allowing a CSRF / SSRF surface. Set to
176
- * `false` if you intentionally serve a cross-origin API without `cors()`
177
- * (rare; almost always a misconfiguration).
171
+ * carry a cross-origin `Origin` header when no {@link cors} hook in the
172
+ * matched route's hook chain allows that origin. Active when
173
+ * {@link AppOptions.secureDefaults} is not `false`. Returns
174
+ * `403 application/problem+json` so the rejection is loud at the network
175
+ * boundary instead of silently allowing a CSRF / SSRF surface. Set to
176
+ * `false` if you intentionally serve a cross-origin API without `cors()`
177
+ * (rare; almost always a misconfiguration).
178
178
  *
179
179
  * @since 0.16.0
180
180
  */
@@ -312,8 +312,8 @@ export interface AppOptions {
312
312
  * is a "secure by default" choice: production deployments should opt in
313
313
  * explicitly so internal APIs do not accidentally publish a browsable
314
314
  * schema.
315
- * - object — full configuration (custom paths, UI choice, title, per-UI
316
- * config, CSP overrides). The `enabled` field on the object can override the
315
+ * - object — full configuration (custom paths, UI choice, title, per-UI
316
+ * config, CSP overrides). The `enabled` field on the object can override the
317
317
  * auto/prod rule.
318
318
  *
319
319
  * The default is `false` so adding a new `App({ ... })` to an existing app
@@ -402,6 +402,19 @@ export interface DocsRouteOptions {
402
402
  * @since 0.39.0
403
403
  */
404
404
  redoc?: RedocConfiguration;
405
+ /**
406
+ * Optional authorization launcher rendered into the docs page. Use it to
407
+ * make Scalar, Swagger UI, and Redoc expose a consistent button that opens
408
+ * a local login form or a third-party identity provider such as Entra ID,
409
+ * Auth0, Better Auth, Clerk, Okta, Keycloak, or any OAuth2/OIDC provider.
410
+ *
411
+ * The button only starts the login/provider flow; API calls are still
412
+ * authorized by the OpenAPI security scheme and the credentials entered or
413
+ * stored by the selected docs UI.
414
+ *
415
+ * @since 0.43.0
416
+ */
417
+ auth?: DocsAuthLauncherOptions;
405
418
  /** Page `<title>`. Defaults to the resolved OpenAPI `info.title`. */
406
419
  title?: string;
407
420
  /**
@@ -848,10 +861,10 @@ export declare class App<Routes extends readonly RouteDefinition<any, any, any,
848
861
  private inflight;
849
862
  private draining;
850
863
  /**
851
- * CORS origin allowlist predicates from the currently active group-level
852
- * hooks. Used for unmatched routes; matched routes use the snapshot stored
853
- * on their compiled route so later `app.use(cors(...))` calls do not
854
- * retroactively loosen earlier routes.
864
+ * CORS origin allowlist predicates from the currently active group-level
865
+ * hooks. Used for unmatched routes; matched routes use the snapshot stored
866
+ * on their compiled route so later `app.use(cors(...))` calls do not
867
+ * retroactively loosen earlier routes.
855
868
  */
856
869
  private corsOriginAllows;
857
870
  /**
@@ -877,14 +890,22 @@ export declare class App<Routes extends readonly RouteDefinition<any, any, any,
877
890
  */
878
891
  private responseBodySchemaAuditDone;
879
892
  /**
880
- * Cached merge of `options.hooks` only. Used on the cold 404/405 path
881
- * and as the baseline for cross-origin guard decisions when no route
882
- * matches.
893
+ * Cached merge of `options.hooks` only. Used on the cold 404/405 path
894
+ * and as the baseline for cross-origin guard decisions when no route
895
+ * matches.
883
896
  */
884
897
  private _globalHooksCache;
885
898
  private _globalCorsAllowsCache;
886
899
  private get globalHooks();
887
900
  private get globalCorsAllows();
901
+ /**
902
+ * Cached merge of `options.hooks` plus every `app.use()` group hook, used on
903
+ * the cold dispatch path (404, 405, and OPTIONS preflight) so perimeter
904
+ * `beforeHandle` guards registered via `app.use()` still cover requests that
905
+ * match no route.
906
+ */
907
+ private _coldPathHooksCache;
908
+ private get coldPathHooks();
888
909
  constructor(options?: AppOptions);
889
910
  /**
890
911
  * Validate {@link AppOptions.disconnectStatusCode}.
@@ -1238,8 +1259,8 @@ export declare class App<Routes extends readonly RouteDefinition<any, any, any,
1238
1259
  * when omitted). Returns `204 No Content` so browsers stop retrying.
1239
1260
  *
1240
1261
  * Combine with `secureHeaders({ reportingEndpoints, reportTo })` to wire
1241
- * the browser to this endpoint. The route is registered as publicly
1242
- * reachable; that is required for the browser
1262
+ * the browser to this endpoint. The route is registered as publicly
1263
+ * reachable; that is required for the browser
1243
1264
  * Reporting API to send to it.
1244
1265
  *
1245
1266
  */