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>
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
# UniverseClient
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
`UniverseClient` is the single composition point that aggregates solar, star, tidal, and weather provider implementations into one cohesive `UniverseScene` snapshot for a given observer at a given instant. It owns no domain knowledge of its own — every datum on the returned scene is delegated to a provider the consumer registered. This indirection lets the same client power a real-time astronomy app, a deterministic game world, a server-rendered ephemeris page, or a unit test, simply by swapping providers.
|
||||
|
||||
The client is intentionally minimal: no caching, no retry, no fan-out; it propagates the caller's `AbortSignal` to every registered provider and assembles their results into one `UniverseScene` value. Tides are skipped when the observer is in space (no surface to compute against). Unregistered domains contribute empty arrays (`bodies`, `stars`) or are omitted entirely (`tides`, `weather`).
|
||||
|
||||
## Features
|
||||
|
||||
- Fluent registration: `registerSolar` / `registerStars` / `registerTides` / `registerWeather` chain on `this`.
|
||||
- One-shot scene assembly via `getScene(observer, time, signal?)`.
|
||||
- AbortSignal forwarded to every provider call.
|
||||
- Tides automatically skipped for `kind: "space"` observers.
|
||||
- Optional fields (`tides`, `weather`) only present when their provider is registered and produces a value.
|
||||
- Provider-agnostic — interfaces only, zero base classes.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { UniverseClient } from "@suaveplan/universe";
|
||||
|
||||
const client = new UniverseClient();
|
||||
const scene = await client.getScene(
|
||||
{ kind: "space", heliocentricVec: { x: 0, y: 0, z: 0 }, frame: "icrs" },
|
||||
new Date()
|
||||
);
|
||||
// scene.bodies === [], scene.stars === [], scene.tides/weather undefined
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { UniverseClient, type UniverseScene } from "@suaveplan/universe";
|
||||
import type {
|
||||
SolarProvider,
|
||||
StarProvider,
|
||||
WeatherProvider,
|
||||
} from "@suaveplan/universe";
|
||||
|
||||
const solar: SolarProvider = {
|
||||
async getBodies() {
|
||||
return [];
|
||||
},
|
||||
async getBody(name) {
|
||||
return {
|
||||
name,
|
||||
type: "star",
|
||||
altitude: 45,
|
||||
azimuth: 180,
|
||||
apparentMagnitude: -26.7,
|
||||
angularDiameterArcmin: 32,
|
||||
distanceAu: 1,
|
||||
heliocentricPosition: { x: 0, y: 0, z: 0 },
|
||||
};
|
||||
},
|
||||
async getSunrise() {
|
||||
return new Date("2026-01-01T06:00:00Z");
|
||||
},
|
||||
async getSunset() {
|
||||
return new Date("2026-01-01T18:00:00Z");
|
||||
},
|
||||
};
|
||||
|
||||
const stars: StarProvider = {
|
||||
async getVisibleStars() {
|
||||
return [];
|
||||
},
|
||||
async queryCone() {
|
||||
return [];
|
||||
},
|
||||
async getStar() {
|
||||
return null;
|
||||
},
|
||||
};
|
||||
|
||||
const weather: WeatherProvider = {
|
||||
async getCurrent() {
|
||||
return { temperature: 18, pressure: 1015, humidity: 60 };
|
||||
},
|
||||
};
|
||||
|
||||
const controller = new AbortController();
|
||||
const client = new UniverseClient()
|
||||
.registerSolar(solar)
|
||||
.registerStars(stars)
|
||||
.registerWeather(weather);
|
||||
|
||||
const scene: UniverseScene = await client.getScene(
|
||||
{
|
||||
kind: "surface",
|
||||
planet: {
|
||||
name: "Earth",
|
||||
mass: 1,
|
||||
radius: 1,
|
||||
polarRadius: 1,
|
||||
surfaceGravity: 1,
|
||||
rotationPeriod: 1,
|
||||
axialTilt: 23.4,
|
||||
atmosphere: null,
|
||||
satellites: [],
|
||||
},
|
||||
coord: { latitude: 51.5, longitude: -0.12 },
|
||||
},
|
||||
new Date(),
|
||||
controller.signal
|
||||
);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `class UniverseClient`
|
||||
|
||||
| Method | Returns | Description |
|
||||
|---|---|---|
|
||||
| `registerSolar(provider)` | `this` | Register a `SolarProvider`. |
|
||||
| `registerStars(provider)` | `this` | Register a `StarProvider`. |
|
||||
| `registerTides(provider)` | `this` | Register a `TidalProvider`. |
|
||||
| `registerWeather(provider)` | `this` | Register a `WeatherProvider`. |
|
||||
| `getScene(observer, time, signal?)` | `Promise<UniverseScene>` | Assemble the scene. Forwards `signal` to every provider. |
|
||||
|
||||
### `interface UniverseScene`
|
||||
|
||||
| Property | Type | Notes |
|
||||
|---|---|---|
|
||||
| `bodies` | `CelestialBody[]` | Empty when no solar provider. |
|
||||
| `stars` | `ObservedStar[]` | Empty when no star provider. |
|
||||
| `tides?` | `TideExtreme[]` | Omitted for space observers and when no tidal provider. |
|
||||
| `weather?` | `WeatherState` | Omitted when no weather provider. |
|
||||
|
||||
The client throws (propagates) any error a provider throws, including `AbortError` from a fired signal.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`UniverseClient` is a coordinator, not a cache. Each `getScene` call invokes every registered provider unconditionally (subject to the space-tide skip). Consumers that need memoisation, retry, or rate limiting should compose those policies into the providers themselves rather than wrapping the client. Re-exporting the four provider interfaces and `WeatherState` from this module (in addition to `@suaveplan/universe/providers/providers`) is intentional so consumers can `import { type SolarProvider } from "@suaveplan/universe"` without reaching into a sub-path.
|
||||
Reference in New Issue
Block a user