first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
# @suaveplan/stars - Star catalog and observation provider: in-memory catalog source, multi-source aggregating provider, cone queries, and observed-star projections built on the @suaveplan/types StarProvider contract.
## Summary
Star catalog provider.
<!-- begin:auto-docs -->
## Documentation tree
- [catalog](./src/catalog/catalog.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [catalog](./src/catalog/catalog.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [provider](./src/provider/provider.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [provider](./src/provider/provider.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [types](./src/types.md) — The types module declares the two foundational shapes that `@suaveplan/stars` is built on: `RawStar`, the lossless cata…
<!-- end:auto-docs --> - [catalog](./src/catalog/catalog.md) — <!-- begin:auto-docs --> _(no submodules)_- [provider](./src/provider/provider.md) — <!-- begin:auto-docs --> _(no submodules)_- [provider](./src/provider/provider.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/types.md) — The types module declares the two foundational shapes that `@suaveplan/stars` is built on: `RawStar`, the lossless cata…
- [catalog](./src/catalog/catalog.md) — <!-- begin:auto-docs --> _(no submodules)_- [provider](./src/provider/provider.md) — <!-- begin:auto-docs --> _(no submodules)_- [provider](./src/provider/provider.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/types.md) — The types module declares the two foundational shapes that `@suaveplan/stars` is built on: `RawStar`, the lossless cata…
- [catalog](./src/catalog/catalog.md) — <!-- begin:auto-docs --> _(no submodules)_- [provider](./src/provider/provider.md) — <!-- begin:auto-docs --> _(no submodules)_- [provider](./src/provider/provider.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/types.md) — The types module declares the two foundational shapes that `@suaveplan/stars` is built on: `RawStar`, the lossless cata…
- [catalog](./src/catalog/catalog.md) — <!-- begin:auto-docs --> _(no submodules)_- [provider](./src/provider/provider.md) — <!-- begin:auto-docs --> _(no submodules)_ - [provider](./src/provider/provider.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/types.md) — The types module declares the two foundational shapes that `@suaveplan/stars` is built on: `RawStar`, the lossless cata…
## Install
```bash
bun add @suaveplan/stars
```

View File

@@ -0,0 +1,50 @@
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
The catalog module provides an in-memory implementation of the `StarCatalogSource` contract used by `@suaveplan/stars` providers. It accepts a static array of `RawStar` records and exposes them through the same `queryCone` and `getStar` surface that production catalog adapters (Hipparcos, Tycho-2, Gaia DR3) implement, so consumers can swap real catalogs for fixtures without touching call sites.
It is the recommended source for tests, demos, offline planetariums, and bootstrap data flows where pulling a remote catalog is unnecessary or undesirable. The implementation favours predictability over scale: lookups are O(n) for cone queries and O(1) for id resolution backed by a single `Map`.
## Features
- Pure in-memory `StarCatalogSource` with no external dependencies.
- Constant-time `getStar(catalogId)` lookup via internal `Map`.
- Naive Cartesian cone filter on `(ra, dec)` for deterministic test output.
- Returns the same `RawStar` shape consumed by `createStarProvider`.
- Zero allocations on the hot path beyond the result array.
## Usage: Basic Example
```ts
import { createInMemoryCatalogSource } from "@suaveplan/stars";
const source = createInMemoryCatalogSource([
{ catalogId: "HIP-32349", ra: 101.287, dec: -16.716, apparentMagnitude: -1.46 },
]);
const sirius = await source.getStar("HIP-32349");
```
## Usage: Advanced Example
```ts
import { createInMemoryCatalogSource, createStarProvider } from "@suaveplan/stars";
const source = createInMemoryCatalogSource([
{ catalogId: "HIP-32349", ra: 101.287, dec: -16.716, apparentMagnitude: -1.46, spectralClass: "A1V", distance: 2.64 },
{ catalogId: "HIP-37279", ra: 114.825, dec: 5.225, apparentMagnitude: 0.4, spectralClass: "F5IV-V" },
]);
const provider = createStarProvider([source]);
const nearby = await provider.queryCone(101, -16, 5);
```
## API Reference
- `createInMemoryCatalogSource(stars: RawStar[]): StarCatalogSource` — builds a source whose `queryCone(ra, dec, radiusDeg)` returns every star inside the Cartesian disk of the given radius (degrees) around the centre, and whose `getStar(catalogId)` returns the matching record or `null`. Both methods are async to satisfy the interface; neither throws.
## Implementation Notes
The cone filter uses Euclidean distance on raw `(ra, dec)` pairs rather than a spherical-trig great-circle distance. This is deliberate: the source is for fixtures and small catalogs, where simplicity and determinism beat correctness near the poles or across the RA wrap. For real-sky use, layer a cosine-correction adapter or replace the source with a HEALPix-backed implementation. The internal `Map` is built once at construction; mutating the input array post-construction is not supported.

View File

@@ -0,0 +1,57 @@
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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<RawStar[]>` — 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.

View File

@@ -0,0 +1,48 @@
## Purpose
The types module declares the two foundational shapes that `@suaveplan/stars` is built on: `RawStar`, the lossless catalog record returned by every source, and `StarCatalogSource`, the source contract that providers compose. They sit deliberately one layer below `@suaveplan/types`'s `CatalogStar` / `ObservedStar` / `StarProvider` so that catalog-backend authors have a stable, narrowly-scoped surface to implement against.
Keeping these types local to the `stars` package — instead of in `@suaveplan/types` — avoids forcing every downstream universe-tier consumer to take on the source-adapter shape, while still letting the provider layer translate cleanly into the public `StarProvider` contract.
## Features
- `RawStar` carries the required astrometry (`catalogId`, `ra`, `dec`, `apparentMagnitude`) plus optional photometric and motion columns (`spectralClass`, `distance`, `properMotionRa`, `properMotionDec`, `parallax`).
- `StarCatalogSource` is a structural interface — any object meeting the shape works, no class inheritance required.
- Async-by-default methods so HTTP-, file-, and DB-backed sources fit without wrapping.
- No runtime cost; the module is types-only and erased at build time.
## Usage: Basic Example
```ts
import type { RawStar, StarCatalogSource } from "@suaveplan/stars";
const star: RawStar = { catalogId: "HIP-32349", ra: 101.287, dec: -16.716, apparentMagnitude: -1.46 };
```
## Usage: Advanced Example
```ts
import type { RawStar, StarCatalogSource } from "@suaveplan/stars";
class HttpCatalogSource implements StarCatalogSource {
constructor(private readonly endpoint: string) {}
async queryCone(ra: number, dec: number, radiusDeg: number): Promise<RawStar[]> {
const url = `${this.endpoint}/cone?ra=${ra}&dec=${dec}&r=${radiusDeg}`;
const res = await fetch(url);
return (await res.json()) as RawStar[];
}
async getStar(catalogId: string): Promise<RawStar | null> {
const res = await fetch(`${this.endpoint}/star/${encodeURIComponent(catalogId)}`);
return res.ok ? ((await res.json()) as RawStar) : null;
}
}
```
## API Reference
- `RawStar` — `{ catalogId: string; ra: number; dec: number; apparentMagnitude: number; spectralClass?: string; distance?: number; properMotionRa?: number; properMotionDec?: number; parallax?: number }`. Right ascension and declination are degrees (J2000); apparent magnitude is the visual band; distance is parsecs; proper motions are mas/yr; parallax is mas.
- `StarCatalogSource` — `{ queryCone(ra, dec, radiusDeg): Promise<RawStar[]>; getStar(catalogId): Promise<RawStar | null> }`. Implementations must be referentially safe (no shared mutable result arrays) and must not throw for missing ids — return `null` instead.
## Implementation Notes
`RawStar` intentionally omits derived horizontal coordinates and extincted magnitudes — those belong on `ObservedStar` and are computed by the provider layer against an observer pose. The optional fields use `T | undefined` rather than nullable so authors can `Object.assign` only when present (see `provider.ts`), which keeps records small and TypeScript happy under `exactOptionalPropertyTypes`.