Files
suaveplan/openspec/archive/2026-05-26-api-openapi-ui-scalar/proposal.md
2026-05-27 23:29:53 +01:00

45 lines
2.4 KiB
Markdown

# `@suaveplan/api-openapi-ui-scalar` — Scalar UI adapter for the `/docs` endpoint
**Package**: `@suaveplan/api-openapi-ui-scalar`
**Status**: PROPOSED
**Type**: new-package
**Stage**: 8 — see umbrella `openspec/changes/api-plugin-foundation/`
## Why
Per design doc §7 the default `/docs` UI is Scalar — modern, fast, low-bundle, supports OpenAPI 3.1 natively. Wrapping it in its own package keeps the surface clean: operators that prefer Swagger or ReDoc swap the package, not the host config logic.
## What changes
- ADDED: `createScalarUiHandler({ openapiUrl, theme, title })` — returns an HTTP handler that serves the Scalar HTML shell pointing at the host's `/openapi.json` URL. Configurable theme / title / default-open-section / search.
- ADDED: Per-plugin variant `createPerPluginScalarUiHandler({ openapiUrlForPlugin, plugin })` — used by the host to mount `/docs/{plugin}`.
- ADDED: `ScalarUiOptions` Zod schema — validates host config when this UI is selected as `host.openapi.ui = "scalar"`.
- ADDED: A static-asset strategy — Scalar's runtime bundle is shipped CDN-or-bundled per `host.openapi.uiAssets` (`"cdn" | "bundled"`); bundled mode embeds the asset under `dist/assets/` for air-gapped hosts.
- ADDED: Error codes (`OPENAPI_UI_SCALAR_*`): `ASSETS_MISSING`, `INVALID_OPTIONS`.
## Out of scope
- Modifying Scalar itself — this is a thin shell.
- Authoring OpenAPI documents — that's `api-openapi`.
- Swagger or ReDoc — sibling packages.
## Source mapping
Genesis-original. Source of design intent: `docs/superpowers/specs/2026-05-13-api-plugin-foundation-design.md`.
| Requirement | Design doc section |
|---|---|
| Default `/docs` UI is Scalar | §7 |
| Pluggable UI (`api-openapi-ui-{scalar,swagger,redoc}`) | §7 |
## Verification approach
- `src/handler/handler.test.ts` — handler returns HTML with the right Scalar bootstrap config; `openapiUrl` is embedded; CSP-friendly nonce supported.
- `src/per-plugin/per-plugin.test.ts` — per-plugin variant points at `/openapi.json?plugin=<name>` (or the host-configured filter URL).
- `src/assets/assets.test.ts` — `"cdn"` vs `"bundled"` modes resolve the right asset URL; missing bundled asset raises `OPENAPI_UI_SCALAR_ASSETS_MISSING`.
- `tests/dep-graph.test.ts` — runtime deps include `api-types`, `error`, `zod`, the Scalar runtime.
## Migration impact
None — additive only. `api-host` selects this when `host.openapi.ui = "scalar"`.