first commit
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
# `factory/create-altair-ui` — Altair UI plugin factory
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`factory/create-altair-ui` is the package's public entry point.
|
||||
`createAltairUi(opts)` validates the caller's options against the Zod
|
||||
schema, builds the asset registry and OTel instruments, and returns a
|
||||
`RouterPlugin` whose `mount(router)` method registers `GET <uiEndpoint>`
|
||||
plus the hashed-asset routes against any `Router` instance. Endpoint
|
||||
collisions are detected up-front via `router.collidesWith` and reject
|
||||
the mount with a typed `GRAPHQL_UI_ALTAIR.ENDPOINT_COLLISION` error
|
||||
before any route is written — partial mounts are impossible.
|
||||
|
||||
## Features
|
||||
|
||||
- Zero-config call: `createAltairUi()` works out of the box.
|
||||
- Returns a frozen `RouterPlugin` with `name`, `options`, `mount`,
|
||||
`renderHtml`, and `renderAsset` members.
|
||||
- HTML response always carries the strict CSP + ancillary security
|
||||
headers.
|
||||
- Asset response carries `Cache-Control: public, max-age=31536000, immutable`.
|
||||
- Asset misses (wrong hash, wrong name) throw `GraphqlUiAltairError`
|
||||
with code `ASSET_MISSING`.
|
||||
- Endpoint collisions throw `GraphqlUiAltairError` with code
|
||||
`ENDPOINT_COLLISION` before any route is registered.
|
||||
- Injectable internals (`assetRegistry`, `instruments`) for integration
|
||||
tests and operators wanting custom asset bundles.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { createAltairUi } from "@suaveplan/api-graphql-ui-altair/factory";
|
||||
import { Router } from "@suaveplan/api-router";
|
||||
|
||||
const router = new Router();
|
||||
const altair = createAltairUi();
|
||||
altair.mount(router);
|
||||
|
||||
// router.match("GET", "/graphql/ui") now resolves to the HTML handler.
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { createAltairUi } from "@suaveplan/api-graphql-ui-altair/factory";
|
||||
import { createAltairInstruments } from "@suaveplan/api-graphql-ui-altair/instruments";
|
||||
import { MeterProvider } from "@opentelemetry/sdk-metrics";
|
||||
import { Router } from "@suaveplan/api-router";
|
||||
|
||||
const meterProvider = new MeterProvider();
|
||||
const instruments = createAltairInstruments({ meterProvider });
|
||||
|
||||
const router = new Router();
|
||||
const altair = createAltairUi(
|
||||
{
|
||||
uiEndpoint: "/dev/altair",
|
||||
graphqlEndpoint: "/api/graphql",
|
||||
theme: "dark",
|
||||
initialEnvironments: {
|
||||
production: {
|
||||
url: "https://api.example.com/graphql",
|
||||
headers: { "x-tenant": "acme" },
|
||||
},
|
||||
},
|
||||
},
|
||||
{ instruments }
|
||||
);
|
||||
altair.mount(router);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `createAltairUi(input?: AltairUiOptionsInput, internals?: CreateAltairUiInternals): RouterPlugin`.
|
||||
- `RouterPlugin` — `{ name, options, mount(router), renderHtml(), renderAsset(hash, name) }`.
|
||||
- `CreateAltairUiInternals` — `{ assetRegistry?, instruments? }`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The factory composes five lower-level modules — options, assets, html,
|
||||
headers, instruments — and exposes their behaviour behind one
|
||||
ergonomic entry point. The `RouterPlugin.options` field is the parsed,
|
||||
defaulted bundle (not the caller's raw input) so downstream code reads
|
||||
the same value the renderer wrote. Frozen-everything posture means
|
||||
operators cannot accidentally mutate the plugin between `mount` calls.
|
||||
Reference in New Issue
Block a user