3.3 KiB
createScalarUiHandler — Scalar HTTP handler factory
(no submodules)
Purpose
The handler module owns the public createScalarUiHandler factory the
host calls when host.openapi.ui = "scalar". It validates the
caller-supplied options through the Zod schema, eagerly resolves the
Scalar runtime asset URL (CDN or bundled), constructs the OTel
instrument bundle, and returns a frozen ScalarUiHandlerBundle whose
handler field is the actual HTTP handler callable. The bundle also
exposes an assetHandler for the bundled-mode <uiEndpoint>/assets/
sub-route the host mounts alongside the main shell.
Features
- Eager validation — invalid options or missing bundled assets fail at handler construction rather than at first request.
- Strict CSP —
Content-Security-Policyheader value is derived once at construction time so request handling never has to recompute it. The policy widens to whitelist the CDN origin only whenassetMode = "cdn". - Per-request CSP nonce passthrough — the handler accepts an optional
nonceon each request which the renderer threads onto the inline<script>blocks. - Idempotent — repeated handler invocations on the same request input return byte-identical body / headers.
- OTel — every successful HTML response increments the
openapi.ui.requests_totalcounter with{ ui: "scalar" }.
Usage: Basic
import { createScalarUiHandler } from "@suaveplan/api-openapi-ui-scalar/handler";
const { handler } = createScalarUiHandler({
openapiUrl: "/openapi.json",
});
const response = handler({ method: "GET", path: "/docs/ui/scalar" });
console.log(response.status); // 200
console.log(response.headers["Content-Security-Policy"]);
Usage: Advanced
import { createScalarUiHandler } from "@suaveplan/api-openapi-ui-scalar/handler";
const bundle = createScalarUiHandler({
openapiUrl: "/openapi.json",
theme: "deepSpace",
layout: "classic",
assetMode: "bundled",
});
// Per-request nonce — wire into your edge / Hono / Worker middleware.
const html = bundle.handler({
method: "GET",
path: "/docs/ui/scalar",
nonce: crypto.randomUUID(),
});
// Bundled-mode hosts ALSO mount the asset handler at
// `<uiEndpoint>/assets/:filename`.
const js = bundle.assetHandler({
method: "GET",
path: `${bundle.options.uiEndpoint}/assets/scalar.js`,
});
console.log(js.headers["Content-Type"]); // "application/javascript; charset=utf-8"
API Reference
CreateScalarUiHandlerInput—ScalarUiOptionsInputplusmeterProvider?andbundledAssetProbe?DI hooks.createScalarUiHandler(input)—ScalarUiHandlerBundle.ScalarUiHandlerBundle—{ name, version, options, instruments, runtimeUrl, handler, assetHandler }(frozen).ScalarUiHandler—(request) => ScalarHttpResponse.
Implementation Notes
The factory pre-computes the CSP header value, the resolved runtime
URL, and the OTel instrument bundle so request handling is a constant-
time render + counter-increment. Mount-time validation catches every
operator-config failure mode before the host accepts traffic. Errors
raised here carry the stable OPENAPI_UI_SCALAR.* codes so host
boot-up can discriminate without unpacking the underlying Zod issues.