Skip to content

Per-UI WithConfiguration for the bundled docs UIs (v0.7.0)#103

Merged
FumingPower3925 merged 2 commits into
mainfrom
per-ui-configuration
Jun 19, 2026
Merged

Per-UI WithConfiguration for the bundled docs UIs (v0.7.0)#103
FumingPower3925 merged 2 commits into
mainfrom
per-ui-configuration

Conversation

@FumingPower3925

Copy link
Copy Markdown
Owner

Milestone v0.7.0. Closes #101 and #102.

Per-UI WithConfiguration (#101)

Each bundled UI sub-package's WithUI now accepts variadic options, with a shared WithConfiguration(map[string]any) that forwards UI-native configuration without forking the template or its CSP:

mux := stdocs.New(scalar.WithUI(
    scalar.WithConfiguration(map[string]any{"theme": "purple", "layout": "modern"}),
))
  • Rendered once in newDocsCore via html/template into the carrier each UI understands: Scalar data-configuration attribute; Swagger UI & Redoc a non-executable <script type="application/json"> block read by a static, hash-pinned initializer; Stoplight <elements-api> attributes.
  • New exported Config.UIConfig; shared internal/uiopt (Apply/Configuration/Merge).
  • Source-compatible: existing WithUI() calls still compile (verified from an external module).

CSP-safe defaults

The UIs now disable, by default, the features that can't work under the strict docs CSP, so there's no dead chrome: Scalar's Ask AI / Generate MCP (call scalar.com) + external fonts, and Swagger UI's validator badge (validator.swagger.io). All overridable via WithConfiguration (top-level); relax the CSP with WithDocsSecurityHeaders(false) / WithCSP. Swagger's inline-init sha256 is re-pinned; Redoc gains one (it now boots via Redoc.init).

Content-Disposition on the spec endpoint (#102)

serveSpec now sends Content-Disposition: inline; filename="openapi.json" (and .yaml) — a sensible save-as name while still rendering in-browser.

Verification

  • gofmt / go build / go vet / -race / golangci-lint all clean across 17 packages; zero runtime deps.
  • Full headless-Chrome uismoke suite passes: defaults hide Scalar's chrome, overrides re-enable it, all UIs boot under their CSP with no violations.
  • New active tests: config-injection neutralized across all 4 UIs, JSON-carrier round-trip, built-in page ignores UIConfig, CSP parity with config.
  • Reviewed by a 22-agent adversarial ship-gate (0 confirmed blockers/majors).

Each ui/* sub-package's WithUI now takes variadic options, with a shared
WithConfiguration(map[string]any) that forwards UI-native configuration
to the page without forking the template or its CSP. The map is rendered
once, in the docs handler, into the carrier each UI understands: a
data-configuration attribute for Scalar, a non-executable
<script type="application/json"> block read by a static, hash-pinned
initializer for Swagger UI and Redoc, and <elements-api> attributes for
Stoplight. A new exported Config.UIConfig field carries it, and a small
internal/uiopt package holds the shared option plumbing.

The UIs also disable, by default, the features that cannot work under the
strict docs CSP, so the page has no dead chrome: Scalar's Ask AI and
Generate MCP (they call scalar.com) and its external fonts, and Swagger
UI's spec-validator badge (validator.swagger.io). These are plain
defaults a caller's WithConfiguration overrides at the top level;
relaxing the CSP so a re-enabled feature can reach its service is
WithDocsSecurityHeaders(false) or WithCSP. Swagger's inline-init hash is
re-pinned, and Redoc gains one (it now boots via Redoc.init rather than
the spec-url web component).

Separately, the spec endpoint now sends Content-Disposition: inline with
a filename, so a direct download gets a sensible name while the document
still renders in the browser.
@FumingPower3925 FumingPower3925 merged commit c83a696 into main Jun 19, 2026
38 checks passed
FumingPower3925 added a commit that referenced this pull request Jun 19, 2026
Each ui/* sub-package's WithUI now takes variadic options, with a shared
WithConfiguration(map[string]any) that forwards UI-native configuration
to the page without forking the template or its CSP. The map is rendered
once, in the docs handler, into the carrier each UI understands: a
data-configuration attribute for Scalar, a non-executable
<script type="application/json"> block read by a static, hash-pinned
initializer for Swagger UI and Redoc, and <elements-api> attributes for
Stoplight. A new exported Config.UIConfig field carries it, and a small
internal/uiopt package holds the shared option plumbing.

The UIs also disable, by default, the features that cannot work under the
strict docs CSP, so the page has no dead chrome: Scalar's Ask AI and
Generate MCP (they call scalar.com) and its external fonts, and Swagger
UI's spec-validator badge (validator.swagger.io). These are plain
defaults a caller's WithConfiguration overrides at the top level;
relaxing the CSP so a re-enabled feature can reach its service is
WithDocsSecurityHeaders(false) or WithCSP. Swagger's inline-init hash is
re-pinned, and Redoc gains one (it now boots via Redoc.init rather than
the spec-url web component).

Separately, the spec endpoint now sends Content-Disposition: inline with
a filename, so a direct download gets a sensible name while the document
still renders in the browser.
@FumingPower3925 FumingPower3925 deleted the per-ui-configuration branch June 19, 2026 09:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose per-UI configuration (e.g. Scalar configuration) via WithUI options

1 participant