Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@suaveplan/api-graphql-ui-altair — Altair GraphQL UI plugin for the Suaveplan API plugin system. Mounts the Altair shell at GET /graphql/ui via createAltairUi(opts), serves bundled (no-CDN) assets from a hashed static map, embeds graphqlEndpoint / subscriptionEndpoint / initialQuery / initialHeaders / initialEnvironments into the shell, attaches a strict CSP (no script 'unsafe-inline'), increments graphql.ui.requests_total{ ui: "altair" } via an injectable MeterProvider, and refuses endpoint collisions with the GRAPHQL_UI_ALTAIR_ENDPOINT_COLLISION code. Structural sibling of api-graphql-ui-graphiql.
Altair GraphQL UI plugin for the Suaveplan API plugin
system. Structural sibling of @suaveplan/api-graphql-ui-graphiql.
Documentation tree
- assets —
assetsships the Altair shell as a static-asset map keyed by logical filename. Every entry carries a content-type, th…- assets —
assetsships the Altair shell as a static-asset map keyed by logical filename. Every entry carries a content-type, th…
- assets —
- error-codes —
error-codesis the package's single source of truth for the two stable error codes the Altair UI plugin emits. Centra…- error-codes —
error-codesis the package's single source of truth for the two stable error codes the Altair UI plugin emits. Centra…
- error-codes —
- factory —
factory/create-altair-uiis the package's public entry point.createAltairUi(opts)validates the caller's options a…- create-altair-ui —
factory/create-altair-uiis the package's public entry point.createAltairUi(opts)validates the caller's options a…
- create-altair-ui —
- headers —
headers/cspproduces the Content-Security-Policy and the two ancillary security headers (X-Content-Type-Options, `R…- csp —
headers/cspproduces the Content-Security-Policy and the two ancillary security headers (X-Content-Type-Options, `R…
- csp —
- html —
html/render-shellproduces the single HTML document the Altair UI plugin serves at<uiEndpoint>. The shell mounts a…- render-shell —
html/render-shellproduces the single HTML document the Altair UI plugin serves at<uiEndpoint>. The shell mounts a…
- render-shell —
- instruments —
instrumentsowns the package's single OpenTelemetry counter,graphql.ui.requests_total, labelled with the constant…- instruments —
instrumentsowns the package's single OpenTelemetry counter,graphql.ui.requests_total, labelled with the constant…
- instruments —
- options —
optionsowns the Zod-validated configuration surface every consumer of the Altair UI plugin passes through. The schem…- options —
optionsowns the Zod-validated configuration surface every consumer of the Altair UI plugin passes through. The schem…
- options —
What this package is
- Opt-in. The host serves nothing at
/graphql/uiunless this plugin (or its GraphiQL sibling) is wired against the router. - Bundled assets only — no CDN. Every asset the HTML shell loads
ships inside this package's
dist/output. The plugin works in air-gapped, offline-first environments. - Alternative to GraphiQL, not co-existing. Operators wire one or
the other against
/graphql/ui. Both at once is refused by host config (the engine adapters return 404 there when neither is wired).
Quick start
import { createAltairUi } from "@suaveplan/api-graphql-ui-altair";
import { Router } from "@suaveplan/api-router";
const router = new Router();
const altair = createAltairUi();
altair.mount(router);
// router.match("GET", "/graphql/ui") resolves to the Altair HTML handler.
Configuration
createAltairUi({
uiEndpoint: "/graphql/ui", // default
graphqlEndpoint: "/graphql", // default
subscriptionEndpoint: "/graphql/ws", // default
theme: "system", // "light" | "dark" | "system"
initialQuery: "",
initialHeaders: { "x-tenant": "acme" },
initialEnvironments: {
production: {
url: "https://api.example.com/graphql",
subscriptionsEndpoint: "wss://api.example.com/graphql",
headers: { "x-env": "prod" },
variables: { region: "us-east-1" },
},
},
});
Security posture
- Strict Content-Security-Policy on every HTML response.
script-src 'self'— no inline scripts.style-src 'self' 'unsafe-inline'— required for the Altair shell.frame-ancestors 'none'— clickjacking defence.X-Content-Type-Options: nosniff,Referrer-Policy: no-referrer.- Static assets carry
Cache-Control: public, max-age=31536000, immutable.
Observability
Emits one OTel counter: graphql.ui.requests_total with label
ui="altair". The metric name is deliberately identical to the
GraphiQL sibling so dashboards can sum across both UIs by dropping
the ui label.
Error codes
GRAPHQL_UI_ALTAIR.ASSET_MISSING— request for a static asset the bundled registry doesn't recognise (404).GRAPHQL_UI_ALTAIR.ENDPOINT_COLLISION—mount()called against a router that already servesGET <uiEndpoint>(typically the GraphiQL sibling is wired against the same path).
License
MIT