_(no submodules)_ ## Purpose The provider module composes one or more `StarCatalogSource` instances into a single `StarProvider` (from `@suaveplan/types`) that consumers — sky renderers, planetarium UIs, telescope planners — can program against without binding to a specific catalog backend. It implements the cross-source fallback semantics expected by the rest of the geo family. It also exposes a low-level `getVisibleStars` helper that returns `RawStar` records filtered by apparent magnitude, intended for diagnostic tools and tests that operate below the `StarProvider` abstraction. ## Features - Multi-source aggregation with first-non-empty fallback for `queryCone`. - First-hit short-circuit for `getStar` across sources. - `getVisibleStars` projects every queried star into an `ObservedStar` with placeholder altitude/azimuth/extincted-magnitude fields suitable for the contract surface. - Total support for the optional `RawStar` columns (`spectralClass`, `distance`, `properMotionRa`, `properMotionDec`, `parallax`) — present fields are forwarded, absent ones omitted under `exactOptionalPropertyTypes`. - Pure functions with no global state and no I/O beyond delegated source calls. ## Usage: Basic Example ```ts import { createInMemoryCatalogSource, createStarProvider } from "@suaveplan/stars"; const source = createInMemoryCatalogSource([ { catalogId: "HIP-32349", ra: 101.287, dec: -16.716, apparentMagnitude: -1.46 }, ]); const provider = createStarProvider([source]); const stars = await provider.queryCone(101, -16, 5); ``` ## Usage: Advanced Example ```ts import { createInMemoryCatalogSource, createStarProvider, getVisibleStars } from "@suaveplan/stars"; const primary = createInMemoryCatalogSource([]); const fallback = createInMemoryCatalogSource([ { catalogId: "HIP-37279", ra: 114.825, dec: 5.225, apparentMagnitude: 0.4 }, { catalogId: "HIP-91262", ra: 279.234, dec: 38.784, apparentMagnitude: 0.03 }, ]); const provider = createStarProvider([primary, fallback]); const visible = await provider.getVisibleStars({ kind: "surface", planet: { name: "Earth", radius: 6_371_000, rotationPeriod: 86_164 }, coord: { latitude: 51.4779, longitude: -0.0015 }, }); const bright = await getVisibleStars([fallback], { latitude: 0, longitude: 0 }, 0, 1); ``` ## API Reference - `createStarProvider(sources: StarCatalogSource[]): StarProvider` — returns a `StarProvider` whose `queryCone(ra, dec, radiusDeg)` walks `sources` in order and returns the first non-empty result mapped to `CatalogStar`; whose `getStar(catalogId)` returns the first match across sources or `null`; and whose `getVisibleStars(observer)` returns every star across all sources projected to `ObservedStar`. - `getVisibleStars(sources, observer, minAltitudeDeg?, maxMagnitude?): Promise` — collects raw stars from every source via a 90-degree cone at the celestial origin and filters by `maxMagnitude` (default 6). `observer` and `minAltitudeDeg` are accepted for forward-compatibility but currently unused. ## Implementation Notes `toCatalogStar` uses guarded `Object.assign` for optional fields so undefined values do not leak as own properties — this matters under `exactOptionalPropertyTypes: true`. `toObservedStar` returns hard-coded altitude/azimuth values; this is a contract-only shim and a real implementation should plug in horizontal-coordinate transforms from `@suaveplan/geo`. `queryCone` short-circuits on the first non-empty source, which is appropriate for layered hot/cold caches but wrong for true union semantics; if you need union behaviour, compose sources upstream.