mirror of
https://github.com/acamarata/pray-calc.git
synced 2026-07-01 03:14:28 +00:00
131 lines
4.6 KiB
Markdown
131 lines
4.6 KiB
Markdown
# Architecture
|
||
|
||
## Module Structure
|
||
|
||
```
|
||
src/
|
||
├── index.ts Main exports
|
||
├── types.ts All interfaces and type aliases
|
||
├── getSolarEphemeris.ts Jean Meeus solar declination, r, ecliptic lon
|
||
├── getMSC.ts MSC piecewise seasonal model
|
||
├── getAngles.ts Dynamic Fajr/Isha angle computation
|
||
├── getAsr.ts Asr from noon + declination
|
||
├── getQiyam.ts Last-third-of-night calculation
|
||
├── getTimes.ts Raw fractional-hour prayer times
|
||
├── calcTimes.ts Formatted HH:MM:SS prayer times
|
||
├── getTimesAll.ts All-methods comparison (raw)
|
||
└── calcTimesAll.ts All-methods comparison (formatted)
|
||
```
|
||
|
||
## Data Flow
|
||
|
||
```
|
||
Date + lat/lng/tz/elev/temp/pressure
|
||
│
|
||
├─► getSolarEphemeris() ──► decl, r, eclLon
|
||
│
|
||
├─► getMscFajr/Isha() ──► minutes offset
|
||
│
|
||
└─► getAngles() ──► fajrAngle, ishaAngle
|
||
│
|
||
▼
|
||
nrel-spa getSpa()
|
||
(batch zenith angles)
|
||
│
|
||
├─► spaData.angles[0].sunrise = Fajr
|
||
├─► spaData.sunrise = Sunrise
|
||
├─► spaData.solarNoon = Noon
|
||
├─► spaData.sunset = Maghrib
|
||
└─► spaData.angles[1].sunset = Isha
|
||
│
|
||
├─► getAsr(noon, lat, decl)
|
||
└─► getQiyam(fajr, isha)
|
||
```
|
||
|
||
For `getTimesAll`, the SPA call is extended to include all method zenith angles:
|
||
|
||
```
|
||
allZeniths = [
|
||
fajrZenith, // dynamic Fajr
|
||
ishaZenith, // dynamic Isha
|
||
...methodZeniths // 14 × 2 = 28 more
|
||
]
|
||
```
|
||
|
||
One SPA call, 30 zenith angles. Methods with fixed-minute Isha (UAQ, Qatar) use a
|
||
placeholder zenith for the SPA call but override the result with `sunset + minutes`.
|
||
The MSC entry uses MSC minutes offsets relative to the SPA-computed sunrise/sunset.
|
||
|
||
## External Dependency
|
||
|
||
The only runtime dependency is `nrel-spa`. It provides:
|
||
|
||
- `getSpa(date, lat, lng, tz, opts, zeniths)`: batch NREL SPA computation
|
||
- `formatTime(fractionalHours)`: converts `5.5` to `"05:30:00"`, returns `"N/A"` for NaN
|
||
|
||
The SPA (Solar Position Algorithm) from the National Renewable Energy Laboratory is
|
||
the reference algorithm for solar position. It is accurate to within ±0.0003° and
|
||
covers dates from -2000 to +6000.
|
||
|
||
## Solar Ephemeris
|
||
|
||
`getSolarEphemeris` implements Jean Meeus, _Astronomical Algorithms_ (2nd ed.),
|
||
Chapter 25. This provides:
|
||
|
||
- Solar declination (δ): accurate to ~0.01°
|
||
- Earth-Sun distance (r) in AU: accurate to ~0.0001 AU
|
||
- Apparent ecliptic longitude (λ) in degrees
|
||
|
||
These values are used by `getAngles` to apply physics corrections to the MSC base
|
||
angle. They are computed independently of the full SPA call using a faster,
|
||
lower-precision path that is sufficient for the correction magnitudes involved.
|
||
|
||
Why not use the SPA declination? The nrel-spa public API does not expose solar
|
||
declination. The SPA computes it internally, but the value is not part of the
|
||
public interface. Rather than monkey-patching nrel-spa or making a second SPA call
|
||
with a known reference point, the Meeus equations provide a clean solution at
|
||
adequate accuracy.
|
||
|
||
## Asr Computation
|
||
|
||
`getAsr` does not call the SPA. Instead, it solves the shadow-ratio equation
|
||
analytically:
|
||
|
||
```
|
||
// Shadow ratio: s = 1 (Shafi'i) or s = 2 (Hanafi)
|
||
altitude = arccot(s + tan(|latitude - declination|))
|
||
cos(hourAngle) = (sin(altitude) - sin(lat)sin(decl)) / (cos(lat)cos(decl))
|
||
asrTime = solarNoon + hourAngle (converted to hours)
|
||
```
|
||
|
||
This is faster than an SPA call and avoids a dependency on internal ephemeris state.
|
||
|
||
## Type System
|
||
|
||
All public types are in `src/types.ts` and re-exported from `src/index.ts`. The key
|
||
distinction is:
|
||
|
||
- `FractionalHours` (`number`): raw output from `getTimes` / `getTimesAll`
|
||
- `TimeString` (`string`): formatted output from `calcTimes` / `calcTimesAll`
|
||
|
||
`PrayerTimesAll` extends `PrayerTimes` rather than duplicating fields. The `Methods`
|
||
map uses string keys (method IDs) rather than a union type, to allow forward
|
||
compatibility without breaking changes when methods are added.
|
||
|
||
## Build
|
||
|
||
`tsup` builds dual CJS/ESM output:
|
||
|
||
```
|
||
dist/
|
||
├── index.cjs CJS bundle
|
||
├── index.mjs ESM bundle
|
||
├── index.d.ts CJS type declarations
|
||
└── index.d.mts ESM type declarations
|
||
```
|
||
|
||
Source maps are included. `sideEffects: false` allows tree-shaking.
|
||
|
||
---
|
||
|
||
_[Back to Home](Home) | [API Reference](API-Reference) | [Dynamic Algorithm](Dynamic-Algorithm)_
|