Files
skills/plugins/document-navigator/docs/api-stack/api/api-graphql-ui-altair/README.md
admin 9bf56a806b Move docs/ package mirror into document-navigator plugin
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>
2026-05-30 01:10:00 +01:00

5.5 KiB

@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 — assets ships the Altair shell as a static-asset map keyed by logical filename. Every entry carries a content-type, th…
    • assets — assets ships the Altair shell as a static-asset map keyed by logical filename. Every entry carries a content-type, th…
  • error-codes — error-codes is the package's single source of truth for the two stable error codes the Altair UI plugin emits. Centra…
    • error-codes — error-codes is the package's single source of truth for the two stable error codes the Altair UI plugin emits. Centra…
  • factory — factory/create-altair-ui is the package's public entry point. createAltairUi(opts) validates the caller's options a…
    • create-altair-ui — factory/create-altair-ui is the package's public entry point. createAltairUi(opts) validates the caller's options a…
  • headers — headers/csp produces the Content-Security-Policy and the two ancillary security headers (X-Content-Type-Options, `R…
    • csp — headers/csp produces the Content-Security-Policy and the two ancillary security headers (X-Content-Type-Options, `R…
  • html — html/render-shell produces the single HTML document the Altair UI plugin serves at <uiEndpoint>. The shell mounts a…
    • render-shell — html/render-shell produces the single HTML document the Altair UI plugin serves at <uiEndpoint>. The shell mounts a…
  • instruments — instruments owns the package's single OpenTelemetry counter, graphql.ui.requests_total, labelled with the constant…
    • instruments — instruments owns the package's single OpenTelemetry counter, graphql.ui.requests_total, labelled with the constant…
  • options — options owns the Zod-validated configuration surface every consumer of the Altair UI plugin passes through. The schem…
    • options — options owns the Zod-validated configuration surface every consumer of the Altair UI plugin passes through. The schem…

What this package is

  • Opt-in. The host serves nothing at /graphql/ui unless 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 serves GET <uiEndpoint> (typically the GraphiQL sibling is wired against the same path).

License

MIT