first commit
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
# Scalar HTML shell renderer
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The render-shell module emits the HTML body returned by the Scalar UI
|
||||
handler. It embeds the configured OpenAPI document URL into a
|
||||
`<script id="scalar-config" type="application/json">` block (inert under
|
||||
strict CSP — JSON is not a script-src vector), references the resolved
|
||||
Scalar runtime URL (CDN or bundled), and renders a small status / path
|
||||
listing placeholder so even the air-gapped bundled bootstrap has
|
||||
something to populate. When the operator runs nonce-based CSP, the
|
||||
`renderShell` API accepts a `nonce` value the renderer threads onto the
|
||||
inline `<script>` tags.
|
||||
|
||||
## Features
|
||||
|
||||
- `escapeHtml(input)` — replaces `& < > " '` with their entity
|
||||
equivalents. Used on every caller-supplied string embedded in the
|
||||
shell.
|
||||
- `renderShell({ options, openapiUrl, runtimeUrl, nonce? })` — emits the
|
||||
full HTML body. The body references `openapiUrl` exactly once in the
|
||||
Scalar configuration block per the requirement spec.
|
||||
- Bundled-mode shells include a `<link rel="stylesheet">` to the local
|
||||
CSS asset; cdn-mode shells omit the link because the upstream Scalar
|
||||
bundle ships its own styles.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { renderShell } from "@suaveplan/api-openapi-ui-scalar/html";
|
||||
import { parseScalarUiOptions } from "@suaveplan/api-openapi-ui-scalar/options";
|
||||
|
||||
const options = parseScalarUiOptions({ openapiUrl: "/openapi.json" });
|
||||
const html = renderShell({
|
||||
options,
|
||||
openapiUrl: "/openapi.json",
|
||||
runtimeUrl: "https://cdn.jsdelivr.net/npm/@scalar/api-reference",
|
||||
});
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { renderShell } from "@suaveplan/api-openapi-ui-scalar/html";
|
||||
import { parseScalarUiOptions } from "@suaveplan/api-openapi-ui-scalar/options";
|
||||
|
||||
const options = parseScalarUiOptions({
|
||||
openapiUrl: "/openapi.json?plugin=billing",
|
||||
theme: "deepSpace",
|
||||
assetMode: "bundled",
|
||||
});
|
||||
|
||||
// Per-request nonce for hosts running nonce-based CSP.
|
||||
const html = renderShell({
|
||||
options,
|
||||
openapiUrl: options.openapiUrl,
|
||||
runtimeUrl: "/docs/ui/scalar/assets/scalar.<hash>.js",
|
||||
nonce: "n-9b2f7c2a",
|
||||
});
|
||||
|
||||
// The body references the configured OpenAPI URL exactly once.
|
||||
console.assert(html.split(options.openapiUrl).length - 1 === 1);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `RenderShellInput` — `{ options, openapiUrl, runtimeUrl, nonce? }`.
|
||||
- `renderShell(input)` — returns the full HTML body string.
|
||||
- `escapeHtml(input)` — entity-escapes the five hazardous characters.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The configuration block JSON is post-processed to replace every `<` with
|
||||
its unicode escape so string values like `"foo</script>"` cannot
|
||||
terminate the script tag. This is the same defence applied by the
|
||||
sibling `api-graphql-ui-graphiql` package; the technique is documented
|
||||
by OWASP and is the strictest path that keeps the policy free of
|
||||
`'unsafe-inline'`. The OpenAPI URL is embedded inside the JSON block
|
||||
exactly once — verified by the handler conformance test.
|
||||
Reference in New Issue
Block a user