Files
skills/docs/api-stack/api/api-openapi-ui-scalar/src/html/render-shell.md
2026-05-29 08:20:56 +01:00

2.9 KiB

Scalar HTML shell renderer

(no submodules)

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

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

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.