Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
# @suaveplan/tides — Tidal Prediction Capability
Universal-tier tidal prediction surface exposing the unified `TidalProvider`
contract from `@suaveplan/types`, three concrete provider factories
(harmonic / equilibrium-physics / ADMIRALTY API), harmonic-constituent math
with nodal corrections, equilibrium-tide physics, and tide-station search.
## Requirements
### Requirement: Harmonic prediction engine
The package SHALL expose `predictHeight(constituents, time, meanSeaLevel?)`
and `findExtremes(constituents, from, to, meanSeaLevel?)` computing tide
height per the harmonic formula `h(t) = H₀ + Σ f(t)·Hₙ·cos(ωₙ·t + V₀ₙ(t) − Gₙ)`
using the J2000 epoch (`2000-01-01T12:00:00Z`) as the time base.
#### Scenario: Empty constituent list rejected
- **WHEN** `predictHeight([], time)` is called with zero constituents
- **THEN** it MUST throw `TideError` with code `NO_CONSTITUENTS`.
#### Scenario: Nodal corrections applied
- **WHEN** `predictHeight` runs over named constituents (M2, S2, K1, …)
- **THEN** the per-constituent node factor `f` and astronomical argument
`V₀` MUST be derived from the time argument via `nodeFactor(name, time)` /
`astronomicalArgument(name, time)` rather than treated as static.
### Requirement: Harmonic-constituent registry
The package SHALL ship `CONSTITUENT_SPEEDS` (degrees/hour angular speeds)
and `DOODSON_NUMBERS` tables for the canonical major constituents
(M2, S2, N2, K2, K1, O1, P1, Q1, M4, …) re-exported from
`./harmonic/harmonic-constituents`.
### Requirement: Equilibrium-tide physics
The package SHALL expose `equilibriumTideHeight(planet, coord, time)` and
`findEquilibriumExtremes(planet, coord, date, signal?)` modelling the
solid-body equilibrium tide on a `PlanetConfig` ellipsoid (consumes
`@suaveplan/geo-planet`).
### Requirement: ADMIRALTY UK Hydrographic Office client
The package SHALL expose `AdmiraltyProvider` and `createAdmiraltyProvider`
binding the ADMIRALTY UK Tidal API
(`https://admiraltyapi.azure-api.net/uktidalapi/api/V1`) with:
- `Ocp-Apim-Subscription-Key` header taken from constructor option `apiKey`.
- Injectable `fetchFn` (defaults to `globalThis.fetch`).
- Configurable `cacheTtlMs` (default `3_600_000`).
#### Scenario: ADMIRALTY API key absent
- **WHEN** `createAdmiraltyProvider({ apiKey: "" })` is called
- **THEN** the resulting provider MUST throw `TideError` (`MISSING_API_KEY`)
on first network call.
### Requirement: Provider factory surface
The package SHALL expose three factories returning the unified
`TidalProvider` shape from `@suaveplan/types`:
- `createTiconProvider(constituents, meanSeaLevel?)` — offline harmonic.
- `createPhysicsBasedProvider(planet)` — equilibrium-tide approximation.
- `createAdmiraltyProvider(options)` — ADMIRALTY UK API.
All three MUST satisfy `predictHeight(planet, coord, time)` and
`getExtremes(planet, coord, date, signal?)`.
### Requirement: Tide-station search
The package SHALL expose `findNearestStation(stations, latitude, longitude)`
returning `NearestStationResult` with great-circle `distanceKm` computed
via `@suaveplan/geo` haversine math.
### Requirement: Typed error surface
The package SHALL expose a frozen `TideError` class with stable codes
covering `NO_CONSTITUENTS`, `MISSING_API_KEY`, `STATION_NOT_FOUND`, and
network/parse failure paths surfaced by the ADMIRALTY provider.
### Requirement: AbortSignal threading
Every async provider call (`predictHeight`, `getExtremes`,
`getNearestStation`, `getStations`) SHALL accept and honour an optional
`AbortSignal`, aborting in-flight ADMIRALTY HTTP requests via the underlying
`fetchFn`.
### Requirement: Universal-tier purity
The package MUST NOT import browser-only or Node-only APIs at module top
level — `fetch` is consumed only through the injectable `fetchFn` so the
package runs unchanged in browser, Bun, and Node environments.
### Requirement: Test + coverage gates
`bunx turbo lint typecheck test --filter=@suaveplan/tides` MUST be green
and `bunx turbo test:coverage --filter=@suaveplan/tides` MUST hit 100%
on touched modules before any release.