first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
# `createScalarUiHandler` — Scalar HTTP handler factory
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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-Policy` header value is derived once at
construction time so request handling never has to recompute it. The
policy widens to whitelist the CDN origin only when `assetMode = "cdn"`.
- Per-request CSP nonce passthrough — the handler accepts an optional
`nonce` on 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_total` counter with `{ ui: "scalar" }`.
## Usage: Basic
```ts
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
```ts
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` — `ScalarUiOptionsInput` plus
`meterProvider?` and `bundledAssetProbe?` 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.