siderust-js 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/.github/workflows/ci.yml +166 -0
  2. package/.gitmodules +9 -0
  3. package/CHANGELOG.md +26 -0
  4. package/LICENSE +661 -0
  5. package/README.md +138 -0
  6. package/package.json +12 -0
  7. package/qtty-js/.github/workflows/ci.yml +151 -0
  8. package/qtty-js/.gitmodules +3 -0
  9. package/qtty-js/CHANGELOG.md +31 -0
  10. package/qtty-js/LICENSE +661 -0
  11. package/qtty-js/README.md +132 -0
  12. package/qtty-js/package.json +20 -0
  13. package/qtty-js/qtty/.github/workflows/ci.yml +155 -0
  14. package/qtty-js/qtty/CHANGELOG.md +120 -0
  15. package/qtty-js/qtty/Cargo.lock +1462 -0
  16. package/qtty-js/qtty/Cargo.toml +12 -0
  17. package/qtty-js/qtty/LICENSE +661 -0
  18. package/qtty-js/qtty/README.md +9 -0
  19. package/qtty-js/qtty/qtty/Cargo.toml +41 -0
  20. package/qtty-js/qtty/qtty/README.md +8 -0
  21. package/qtty-js/qtty/qtty/examples/angles.rs +14 -0
  22. package/qtty-js/qtty/qtty/examples/astronomy.rs +17 -0
  23. package/qtty-js/qtty/qtty/examples/dimensional_arithmetic.rs +83 -0
  24. package/qtty-js/qtty/qtty/examples/python_integration.rs +61 -0
  25. package/qtty-js/qtty/qtty/examples/quickstart.rs +15 -0
  26. package/qtty-js/qtty/qtty/examples/ratios.rs +12 -0
  27. package/qtty-js/qtty/qtty/examples/serde_with_unit.rs +234 -0
  28. package/qtty-js/qtty/qtty/examples/serialization.rs +141 -0
  29. package/qtty-js/qtty/qtty/examples/serialization_advanced.rs +155 -0
  30. package/qtty-js/qtty/qtty/src/f32.rs +108 -0
  31. package/qtty-js/qtty/qtty/src/f64.rs +30 -0
  32. package/qtty-js/qtty/qtty/src/i128.rs +111 -0
  33. package/qtty-js/qtty/qtty/src/i16.rs +111 -0
  34. package/qtty-js/qtty/qtty/src/i32.rs +111 -0
  35. package/qtty-js/qtty/qtty/src/i64.rs +111 -0
  36. package/qtty-js/qtty/qtty/src/i8.rs +111 -0
  37. package/qtty-js/qtty/qtty/src/lib.rs +238 -0
  38. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/Cargo.lock +83 -0
  39. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/Cargo.toml +10 -0
  40. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/src/lib.rs +7 -0
  41. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/Cargo.lock +83 -0
  42. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/Cargo.toml +10 -0
  43. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/src/lib.rs +7 -0
  44. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/Cargo.lock +83 -0
  45. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/Cargo.toml +10 -0
  46. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/src/lib.rs +5 -0
  47. package/qtty-js/qtty/qtty/tests/integration_tests.rs +529 -0
  48. package/qtty-js/qtty/qtty/tests/qtty_vec_feature_matrix.rs +58 -0
  49. package/qtty-js/qtty/qtty-core/Cargo.toml +41 -0
  50. package/qtty-js/qtty/qtty-core/README.md +8 -0
  51. package/qtty-js/qtty/qtty-core/examples/diesel_integration.rs +145 -0
  52. package/qtty-js/qtty/qtty-core/examples/quantity_db_serde.rs +215 -0
  53. package/qtty-js/qtty/qtty-core/src/dimension.rs +249 -0
  54. package/qtty-js/qtty/qtty-core/src/feature_diesel.rs +318 -0
  55. package/qtty-js/qtty/qtty-core/src/feature_pyo3.rs +27 -0
  56. package/qtty-js/qtty/qtty-core/src/feature_serde.rs +203 -0
  57. package/qtty-js/qtty/qtty-core/src/feature_tiberius.rs +28 -0
  58. package/qtty-js/qtty/qtty-core/src/lib.rs +744 -0
  59. package/qtty-js/qtty/qtty-core/src/macros.rs +93 -0
  60. package/qtty-js/qtty/qtty-core/src/quantity.rs +810 -0
  61. package/qtty-js/qtty/qtty-core/src/scalar.rs +1742 -0
  62. package/qtty-js/qtty/qtty-core/src/unit.rs +332 -0
  63. package/qtty-js/qtty/qtty-core/src/units/angular.rs +1228 -0
  64. package/qtty-js/qtty/qtty-core/src/units/area.rs +243 -0
  65. package/qtty-js/qtty/qtty-core/src/units/frequency.rs +179 -0
  66. package/qtty-js/qtty/qtty-core/src/units/length.rs +1270 -0
  67. package/qtty-js/qtty/qtty-core/src/units/mass.rs +488 -0
  68. package/qtty-js/qtty/qtty-core/src/units/mod.rs +26 -0
  69. package/qtty-js/qtty/qtty-core/src/units/power.rs +324 -0
  70. package/qtty-js/qtty/qtty-core/src/units/time.rs +667 -0
  71. package/qtty-js/qtty/qtty-core/src/units/unitless.rs +212 -0
  72. package/qtty-js/qtty/qtty-core/src/units/velocity.rs +210 -0
  73. package/qtty-js/qtty/qtty-core/src/units/volume.rs +269 -0
  74. package/qtty-js/qtty/qtty-core/tests/core.rs +628 -0
  75. package/qtty-js/qtty/qtty-core/tests/diesel.rs +461 -0
  76. package/qtty-js/qtty/qtty-core/tests/integers.rs +632 -0
  77. package/qtty-js/qtty/qtty-core/tests/no_cross_unit_ops.rs +35 -0
  78. package/qtty-js/qtty/qtty-core/tests/pyo3.rs +334 -0
  79. package/qtty-js/qtty/qtty-core/tests/quantity_f32.rs +276 -0
  80. package/qtty-js/qtty/qtty-core/tests/scalar_decimal.rs +258 -0
  81. package/qtty-js/qtty/qtty-core/tests/scalar_f32.rs +286 -0
  82. package/qtty-js/qtty/qtty-core/tests/scalar_f64_real.rs +287 -0
  83. package/qtty-js/qtty/qtty-core/tests/scalar_rational.rs +260 -0
  84. package/qtty-js/qtty/qtty-core/tests/serde.rs +256 -0
  85. package/qtty-js/qtty/qtty-core/tests/tiberius.rs +208 -0
  86. package/qtty-js/qtty/qtty-derive/Cargo.toml +23 -0
  87. package/qtty-js/qtty/qtty-derive/README.md +8 -0
  88. package/qtty-js/qtty/qtty-derive/src/lib.rs +340 -0
  89. package/qtty-js/qtty/qtty-ffi/ARCHITECTURE.md +3 -0
  90. package/qtty-js/qtty/qtty-ffi/Cargo.toml +31 -0
  91. package/qtty-js/qtty/qtty-ffi/README.md +9 -0
  92. package/qtty-js/qtty/qtty-ffi/build.rs +326 -0
  93. package/qtty-js/qtty/qtty-ffi/cbindgen.toml +105 -0
  94. package/qtty-js/qtty/qtty-ffi/include/qtty_ffi.h +1126 -0
  95. package/qtty-js/qtty/qtty-ffi/src/ffi.rs +1251 -0
  96. package/qtty-js/qtty/qtty-ffi/src/ffi_serde.rs +294 -0
  97. package/qtty-js/qtty/qtty-ffi/src/helpers.rs +310 -0
  98. package/qtty-js/qtty/qtty-ffi/src/lib.rs +229 -0
  99. package/qtty-js/qtty/qtty-ffi/src/macros.rs +121 -0
  100. package/qtty-js/qtty/qtty-ffi/src/registry.rs +274 -0
  101. package/qtty-js/qtty/qtty-ffi/src/types.rs +620 -0
  102. package/qtty-js/qtty/qtty-ffi/tests/integration_tests.rs +842 -0
  103. package/qtty-js/qtty/qtty-ffi/units.csv +156 -0
  104. package/qtty-js/qtty/qtty-ffi/units.csv.md +3 -0
  105. package/qtty-js/qtty-node/.prettierignore +6 -0
  106. package/qtty-js/qtty-node/.prettierrc.json +6 -0
  107. package/qtty-js/qtty-node/README.md +250 -0
  108. package/qtty-js/qtty-node/c8.config.json +11 -0
  109. package/qtty-js/qtty-node/eslint.config.js +31 -0
  110. package/qtty-js/qtty-node/examples/arithmetic.mjs +64 -0
  111. package/qtty-js/qtty-node/examples/astronomy.mjs +90 -0
  112. package/qtty-js/qtty-node/examples/quickstart.mjs +36 -0
  113. package/qtty-js/qtty-node/examples/serialization.mjs +125 -0
  114. package/qtty-js/qtty-node/examples/unit_factories.mjs +74 -0
  115. package/qtty-js/qtty-node/index.d.ts +219 -0
  116. package/qtty-js/qtty-node/index.js +323 -0
  117. package/qtty-js/qtty-node/lib/DerivedQuantity.js +122 -0
  118. package/qtty-js/qtty-node/lib/Quantity.js +151 -0
  119. package/qtty-js/qtty-node/lib/backend.js +25 -0
  120. package/qtty-js/qtty-node/native.cjs +306 -0
  121. package/qtty-js/qtty-node/package-lock.json +3223 -0
  122. package/qtty-js/qtty-node/package.json +70 -0
  123. package/qtty-js/qtty-node/units.d.ts +299 -0
  124. package/qtty-js/qtty-node/units.js +210 -0
  125. package/qtty-js/qtty-web/Cargo.lock +767 -0
  126. package/qtty-js/qtty-web/Cargo.toml +21 -0
  127. package/qtty-js/qtty-web/index.d.ts +140 -0
  128. package/qtty-js/qtty-web/index.js +20 -0
  129. package/qtty-js/qtty-web/lib/DerivedQuantity.js +58 -0
  130. package/qtty-js/qtty-web/lib/Quantity.js +75 -0
  131. package/qtty-js/qtty-web/lib/backend.js +80 -0
  132. package/qtty-js/qtty-web/package.json +45 -0
  133. package/qtty-js/qtty-web/src/lib.rs +111 -0
  134. package/qtty-js/scripts/ci.sh +73 -0
  135. package/scripts/ci.sh +123 -0
  136. package/siderust-core/Cargo.lock +787 -0
  137. package/siderust-core/Cargo.toml +18 -0
  138. package/siderust-core/DEDUPLICATION.md +124 -0
  139. package/siderust-core/src/body.rs +120 -0
  140. package/siderust-core/src/events.rs +184 -0
  141. package/siderust-core/src/lib.rs +20 -0
  142. package/siderust-core/src/observer.rs +55 -0
  143. package/siderust-core/src/position.rs +213 -0
  144. package/siderust-node/.prettierignore +7 -0
  145. package/siderust-node/.prettierrc.json +6 -0
  146. package/siderust-node/Cargo.lock +906 -0
  147. package/siderust-node/Cargo.toml +29 -0
  148. package/siderust-node/README.md +109 -0
  149. package/siderust-node/__test__/index.test.mjs +248 -0
  150. package/siderust-node/build.rs +5 -0
  151. package/siderust-node/c8.config.json +3 -0
  152. package/siderust-node/eslint.config.js +31 -0
  153. package/siderust-node/examples/01_basic_coordinates.mjs +24 -0
  154. package/siderust-node/examples/02_coordinate_transformations.mjs +25 -0
  155. package/siderust-node/examples/03_all_frames_conversions.mjs +26 -0
  156. package/siderust-node/examples/04_all_center_conversions.mjs +24 -0
  157. package/siderust-node/examples/05_target_tracking.mjs +22 -0
  158. package/siderust-node/examples/06_night_events.mjs +18 -0
  159. package/siderust-node/examples/07_moon_properties.mjs +21 -0
  160. package/siderust-node/examples/08_solar_system.mjs +19 -0
  161. package/siderust-node/examples/09_star_observability.mjs +22 -0
  162. package/siderust-node/examples/10_time_periods.mjs +9 -0
  163. package/siderust-node/examples/11_serialization.mjs +31 -0
  164. package/siderust-node/examples/12_runtime_ephemeris.mjs +27 -0
  165. package/siderust-node/examples/13_coordinate_operations.mjs +20 -0
  166. package/siderust-node/index.d.ts +623 -0
  167. package/siderust-node/index.js +79 -0
  168. package/siderust-node/lib/Observer.js +112 -0
  169. package/siderust-node/lib/Star.js +118 -0
  170. package/siderust-node/lib/backend.js +63 -0
  171. package/siderust-node/lib/wrappers.js +566 -0
  172. package/siderust-node/main.js +20 -0
  173. package/siderust-node/native.cjs +360 -0
  174. package/siderust-node/package-lock.json +3261 -0
  175. package/siderust-node/package.json +71 -0
  176. package/siderust-node/src/body.rs +74 -0
  177. package/siderust-node/src/coordinates.rs +372 -0
  178. package/siderust-node/src/ephemeris.rs +462 -0
  179. package/siderust-node/src/events.rs +577 -0
  180. package/siderust-node/src/lib.rs +43 -0
  181. package/siderust-node/src/observer.rs +132 -0
  182. package/siderust-node/src/phase.rs +218 -0
  183. package/siderust-node/src/position.rs +292 -0
  184. package/siderust-node/src/star.rs +200 -0
  185. package/siderust-web/Cargo.lock +855 -0
  186. package/siderust-web/Cargo.toml +34 -0
  187. package/siderust-web/README.md +100 -0
  188. package/siderust-web/__test__/index.test.mjs +118 -0
  189. package/siderust-web/examples/github-pages/README.md +31 -0
  190. package/siderust-web/examples/github-pages/index.html +135 -0
  191. package/siderust-web/index.d.ts +311 -0
  192. package/siderust-web/index.js +66 -0
  193. package/siderust-web/lib/Observer.js +103 -0
  194. package/siderust-web/lib/Star.js +116 -0
  195. package/siderust-web/lib/backend.js +400 -0
  196. package/siderust-web/lib/wrappers.js +512 -0
  197. package/siderust-web/package.json +55 -0
  198. package/siderust-web/src/body.rs +69 -0
  199. package/siderust-web/src/coordinates.rs +302 -0
  200. package/siderust-web/src/ephemeris.rs +456 -0
  201. package/siderust-web/src/events.rs +520 -0
  202. package/siderust-web/src/lib.rs +51 -0
  203. package/siderust-web/src/observer.rs +117 -0
  204. package/siderust-web/src/phase.rs +190 -0
  205. package/siderust-web/src/position.rs +291 -0
  206. package/siderust-web/src/star.rs +178 -0
  207. package/tempoch-js/.github/workflows/ci.yml +142 -0
  208. package/tempoch-js/.gitmodules +3 -0
  209. package/tempoch-js/CHANGELOG.md +25 -0
  210. package/tempoch-js/LICENSE +661 -0
  211. package/tempoch-js/README.md +126 -0
  212. package/tempoch-js/package.json +20 -0
  213. package/tempoch-js/scripts/ci.sh +73 -0
  214. package/tempoch-js/tempoch/.github/workflows/ci.yml +113 -0
  215. package/tempoch-js/tempoch/CHANGELOG.md +82 -0
  216. package/tempoch-js/tempoch/Cargo.lock +947 -0
  217. package/tempoch-js/tempoch/Cargo.toml +3 -0
  218. package/tempoch-js/tempoch/LICENSE +661 -0
  219. package/tempoch-js/tempoch/README.md +76 -0
  220. package/tempoch-js/tempoch/tempoch/Cargo.toml +27 -0
  221. package/tempoch-js/tempoch/tempoch/examples/periods.rs +45 -0
  222. package/tempoch-js/tempoch/tempoch/examples/quickstart.rs +13 -0
  223. package/tempoch-js/tempoch/tempoch/src/lib.rs +49 -0
  224. package/tempoch-js/tempoch/tempoch/tests/integration.rs +57 -0
  225. package/tempoch-js/tempoch/tempoch-core/Cargo.toml +24 -0
  226. package/tempoch-js/tempoch/tempoch-core/src/delta_t.rs +345 -0
  227. package/tempoch-js/tempoch/tempoch-core/src/instant.rs +811 -0
  228. package/tempoch-js/tempoch/tempoch-core/src/julian_date_ext.rs +142 -0
  229. package/tempoch-js/tempoch/tempoch-core/src/lib.rs +81 -0
  230. package/tempoch-js/tempoch/tempoch-core/src/period.rs +1168 -0
  231. package/tempoch-js/tempoch/tempoch-core/src/scales.rs +779 -0
  232. package/tempoch-js/tempoch/tempoch-ffi/Cargo.lock +889 -0
  233. package/tempoch-js/tempoch/tempoch-ffi/Cargo.toml +26 -0
  234. package/tempoch-js/tempoch/tempoch-ffi/build.rs +24 -0
  235. package/tempoch-js/tempoch/tempoch-ffi/cbindgen.toml +30 -0
  236. package/tempoch-js/tempoch/tempoch-ffi/src/error.rs +19 -0
  237. package/tempoch-js/tempoch/tempoch-ffi/src/lib.rs +82 -0
  238. package/tempoch-js/tempoch/tempoch-ffi/src/period.rs +101 -0
  239. package/tempoch-js/tempoch/tempoch-ffi/src/time.rs +711 -0
  240. package/tempoch-js/tempoch/tempoch-ffi/tests/ffi.rs +265 -0
  241. package/tempoch-js/tempoch-node/.prettierignore +6 -0
  242. package/tempoch-js/tempoch-node/.prettierrc.json +6 -0
  243. package/tempoch-js/tempoch-node/Cargo.lock +496 -0
  244. package/tempoch-js/tempoch-node/Cargo.toml +29 -0
  245. package/tempoch-js/tempoch-node/README.md +265 -0
  246. package/tempoch-js/tempoch-node/__test__/index.test.mjs +598 -0
  247. package/tempoch-js/tempoch-node/build.rs +5 -0
  248. package/tempoch-js/tempoch-node/c8.config.json +3 -0
  249. package/tempoch-js/tempoch-node/eslint.config.js +31 -0
  250. package/tempoch-js/tempoch-node/examples/periods.mjs +79 -0
  251. package/tempoch-js/tempoch-node/examples/quickstart.mjs +71 -0
  252. package/tempoch-js/tempoch-node/examples/timescales.mjs +92 -0
  253. package/tempoch-js/tempoch-node/index.d.ts +280 -0
  254. package/tempoch-js/tempoch-node/index.js +32 -0
  255. package/tempoch-js/tempoch-node/lib/JulianDate.js +176 -0
  256. package/tempoch-js/tempoch-node/lib/ModifiedJulianDate.js +156 -0
  257. package/tempoch-js/tempoch-node/lib/Period.js +133 -0
  258. package/tempoch-js/tempoch-node/lib/backend.js +38 -0
  259. package/tempoch-js/tempoch-node/lib/qttyCompat.js +92 -0
  260. package/tempoch-js/tempoch-node/native.cjs +317 -0
  261. package/tempoch-js/tempoch-node/package-lock.json +3223 -0
  262. package/tempoch-js/tempoch-node/package.json +56 -0
  263. package/tempoch-js/tempoch-node/src/lib.rs +573 -0
  264. package/tempoch-js/tempoch-web/Cargo.toml +23 -0
  265. package/tempoch-js/tempoch-web/index.d.ts +95 -0
  266. package/tempoch-js/tempoch-web/index.js +27 -0
  267. package/tempoch-js/tempoch-web/lib/JulianDate.js +170 -0
  268. package/tempoch-js/tempoch-web/lib/ModifiedJulianDate.js +145 -0
  269. package/tempoch-js/tempoch-web/lib/Period.js +121 -0
  270. package/tempoch-js/tempoch-web/lib/backend.js +118 -0
  271. package/tempoch-js/tempoch-web/package.json +46 -0
  272. package/tempoch-js/tempoch-web/src/lib.rs +184 -0
@@ -0,0 +1,29 @@
1
+ [package]
2
+ name = "siderust-node"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ authors = ["VPRamon <vallespuigramon@gmail.com>"]
6
+ license = "AGPL-3.0"
7
+ repository = "https://github.com/Siderust/siderust"
8
+ description = "Node.js native bindings for siderust — high-precision astronomy and satellite mechanics"
9
+ readme = "README.md"
10
+
11
+ [lib]
12
+ crate-type = ["cdylib"]
13
+
14
+ [dependencies]
15
+ siderust = { version = "0.6.0", features = [] }
16
+ siderust-binding-core = { path = "../siderust-core" }
17
+ qtty = "0.4.1"
18
+ tempoch = "0.4"
19
+ affn = { version = "0.4.1", features = ["astro"] }
20
+ chrono = "0.4.44"
21
+ napi = { version = "2", features = ["napi6"] }
22
+ napi-derive = "2"
23
+
24
+ [build-dependencies]
25
+ napi-build = "2"
26
+
27
+ [profile.release]
28
+ lto = true
29
+ strip = "symbols"
@@ -0,0 +1,109 @@
1
+ # `@siderust/siderust`
2
+
3
+ High-precision astronomy for Node.js with a strict typed boundary.
4
+
5
+ Time inputs use `@siderust/tempoch`. Physical quantities use
6
+ `@siderust/qtty`. Raw numbers are no longer accepted for domain values such
7
+ as epochs, angles, lengths, or observer/star properties.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install @siderust/siderust @siderust/qtty @siderust/tempoch
13
+ ```
14
+
15
+ ## Example
16
+
17
+ ```js
18
+ const { Quantity } = require('@siderust/qtty');
19
+ const { JulianDate, ModifiedJulianDate, Period } = require('@siderust/tempoch');
20
+ const {
21
+ Observer,
22
+ bodyAltitudeAt,
23
+ bodyCrossings,
24
+ moonPhase,
25
+ vsop87Heliocentric,
26
+ } = require('@siderust/siderust');
27
+
28
+ const DEG = (value) => new Quantity(value, 'Degree');
29
+ const M = (value) => new Quantity(value, 'Meter');
30
+
31
+ const observer = new Observer(DEG(-17.8925), DEG(28.7543), M(2396));
32
+ const jd = new JulianDate(2_451_545.0);
33
+ const mjd = new ModifiedJulianDate(60_000.0);
34
+ const window = new Period(mjd, new ModifiedJulianDate(60_001.0));
35
+
36
+ const sunAltitude = bodyAltitudeAt('Sun', observer, mjd);
37
+ const sunCrossings = bodyCrossings('Sun', observer, window, DEG(0));
38
+ const moon = moonPhase(jd);
39
+ const mars = vsop87Heliocentric('Mars', jd);
40
+
41
+ console.log(sunAltitude.toString());
42
+ console.log(sunCrossings[0].mjd.value);
43
+ console.log(moon.phaseAngle.toString());
44
+ console.log(mars.x.toString());
45
+ ```
46
+
47
+ ## Public API
48
+
49
+ ### Domain classes
50
+
51
+ - `new Observer(lon, lat, height)`
52
+ `lon` / `lat` must be angle `Quantity` values and `height` must be a length `Quantity`.
53
+ - `new Star(name, distance, mass, radius, luminosity, ra, dec)`
54
+ Every physical field must be a `Quantity`.
55
+
56
+ ### Time-aware functions
57
+
58
+ - Any `jd` parameter requires a `JulianDate`.
59
+ - Any instantaneous `mjd` parameter requires a `ModifiedJulianDate`.
60
+ - Search windows use `Period`.
61
+
62
+ ### Typed outputs
63
+
64
+ - Angular results return `Quantity` values in degrees.
65
+ - Cartesian positions return `Quantity` coordinates in their documented units.
66
+ - Event timestamps return `ModifiedJulianDate`.
67
+ - Interval results return `Period[]`.
68
+
69
+ ## Main exports
70
+
71
+ - `transformDirection(polar, azimuth, srcFrame, dstFrame, jd)`
72
+ - `directionToHorizontal(polar, azimuth, srcFrame, jd, observer)`
73
+ - `geodeticToEcef(observer)`
74
+ - `angularSeparation(...)`
75
+ - `cartesianDistance(...)`
76
+ - `cartesianMagnitude(...)`
77
+ - `directionToCartesian(polar, azimuth)`
78
+ - `vsop87Heliocentric(body, jd)`
79
+ - `vsop87Barycentric(body, jd)`
80
+ - `vsop87SunBarycentric(jd)`
81
+ - `vsop87EarthBarycentric(jd)`
82
+ - `vsop87EarthHeliocentric(jd)`
83
+ - `vsop87MoonGeocentric(jd)`
84
+ - `transformPositionCenter(x, y, z, srcCenter, dstCenter, jd)`
85
+ - `transformPositionFrame(x, y, z, srcFrame, dstFrame, jd)`
86
+ - `orbitalPeriod(name)`
87
+ - `bodyAltitudeAt(body, observer, mjd)`
88
+ - `bodyAzimuthAt(body, observer, mjd)`
89
+ - `bodyCrossings(body, observer, window, threshold)`
90
+ - `bodyCulminations(body, observer, window)`
91
+ - `bodyAboveThreshold(body, observer, window, threshold)`
92
+ - `bodyBelowThreshold(body, observer, window, threshold)`
93
+ - `bodyAzimuthCrossings(body, observer, window, bearing)`
94
+ - `bodyAzimuthExtrema(body, observer, window)`
95
+ - `starAltitudeAt(star, observer, mjd)`
96
+ - `starAzimuthAt(star, observer, mjd)`
97
+ - `starCrossings(star, observer, window, threshold)`
98
+ - `starCulminations(star, observer, window)`
99
+ - `starAboveThreshold(star, observer, window, threshold)`
100
+ - `starBelowThreshold(star, observer, window, threshold)`
101
+ - `starAzimuthCrossings(star, observer, window, bearing)`
102
+ - `starAzimuthExtrema(star, observer, window)`
103
+ - `intersectPeriods(periods1, periods2)`
104
+ - `moonPhase(jd)`
105
+ - `moonPhaseTopocentric(jd, observer)`
106
+ - `findPhaseEvents(window)`
107
+ - `moonIlluminationAbove(window, kMin)`
108
+ - `moonIlluminationBelow(window, kMax)`
109
+ - `moonIlluminationRange(window, kMin, kMax)`
@@ -0,0 +1,248 @@
1
+ // @ts-check
2
+ import { describe, it } from 'node:test';
3
+ import assert from 'node:assert/strict';
4
+ import { createRequire } from 'node:module';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { dirname, join } from 'node:path';
7
+
8
+ import { Quantity } from '@siderust/qtty';
9
+ import { JulianDate, ModifiedJulianDate, Period } from '@siderust/tempoch';
10
+
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ const require = createRequire(import.meta.url);
13
+
14
+ const {
15
+ Observer,
16
+ Star,
17
+ angularSeparation,
18
+ bodyAltitudeAt,
19
+ bodyCrossings,
20
+ bodyCulminations,
21
+ directionToCartesian,
22
+ directionToHorizontal,
23
+ findPhaseEvents,
24
+ geodeticToEcef,
25
+ getPlanet,
26
+ intersectPeriods,
27
+ moonIlluminationAbove,
28
+ moonPhase,
29
+ orbitalPeriod,
30
+ starAltitudeAt,
31
+ transformDirection,
32
+ transformPositionCenter,
33
+ version,
34
+ vsop87Heliocentric,
35
+ vsop87MoonGeocentric,
36
+ } = require(join(__dirname, '..'));
37
+
38
+ const DEG = (value) => new Quantity(value, 'Degree');
39
+ const M = (value) => new Quantity(value, 'Meter');
40
+ const AU = (value) => new Quantity(value, 'AstronomicalUnit');
41
+ const LY = (value) => new Quantity(value, 'LightYear');
42
+ const SOLAR_MASS = (value) => new Quantity(value, 'SolarMass');
43
+ const SOLAR_RADIUS = (value) => new Quantity(value, 'NominalSolarRadius');
44
+ const SOLAR_LUMINOSITY = (value) => new Quantity(value, 'SolarLuminosity');
45
+
46
+ const J2000 = new JulianDate(2_451_545.0);
47
+ const MJD_60000 = new ModifiedJulianDate(60_000.0);
48
+ const WINDOW = new Period(new ModifiedJulianDate(60_000.0), new ModifiedJulianDate(60_002.0));
49
+
50
+ describe('version()', () => {
51
+ it('returns a semver-like string', () => {
52
+ assert.match(version(), /^\d+\.\d+\.\d+/);
53
+ });
54
+ });
55
+
56
+ describe('Observer', () => {
57
+ it('requires Quantity inputs and exposes typed getters', () => {
58
+ const observer = new Observer(DEG(-17.8925), DEG(28.7543), M(2396));
59
+ assert.equal(observer.lon.unit, 'Degree');
60
+ assert.equal(observer.lat.unit, 'Degree');
61
+ assert.equal(observer.height.unit, 'Meter');
62
+ assert.match(observer.format(), /Observer/);
63
+ });
64
+
65
+ it('rejects raw numbers', () => {
66
+ assert.throws(() => new Observer(-17.8925, 28.7543, 2396), /expected a Quantity/);
67
+ });
68
+ });
69
+
70
+ describe('Star', () => {
71
+ it('requires Quantity inputs and exposes typed getters', () => {
72
+ const star = new Star(
73
+ 'TypedStar',
74
+ LY(100),
75
+ SOLAR_MASS(2),
76
+ SOLAR_RADIUS(1.5),
77
+ SOLAR_LUMINOSITY(8),
78
+ DEG(180),
79
+ DEG(-45),
80
+ );
81
+
82
+ assert.equal(star.distance.unit, 'LightYear');
83
+ assert.equal(star.mass.unit, 'SolarMass');
84
+ assert.equal(star.ra.unit, 'Degree');
85
+ assert.match(star.format(), /TypedStar/);
86
+ });
87
+
88
+ it('rejects raw numbers', () => {
89
+ assert.throws(() => new Star('Broken', 1, 1, 1, 1, 1, 1), /expected a Quantity/);
90
+ });
91
+ });
92
+
93
+ describe('typed outputs', () => {
94
+ it('returns typed planet metadata', () => {
95
+ const mars = getPlanet('Mars');
96
+ assert.equal(mars.mass.unit, 'Kilogram');
97
+ assert.equal(mars.radius.unit, 'Kilometer');
98
+ assert.equal(mars.semiMajorAxis.unit, 'AstronomicalUnit');
99
+ assert.equal(typeof mars.eccentricity, 'number');
100
+ assert.equal(mars.inclination.unit, 'Degree');
101
+ });
102
+
103
+ it('returns typed geodetic coordinates', () => {
104
+ const ecef = geodeticToEcef(Observer.roqueDeLasMuchachos());
105
+ assert.equal(ecef.x.unit, 'Meter');
106
+ assert.equal(ecef.y.unit, 'Meter');
107
+ assert.equal(ecef.z.unit, 'Meter');
108
+ });
109
+
110
+ it('returns typed ephemeris positions', () => {
111
+ const mars = vsop87Heliocentric('Mars', J2000);
112
+ const moon = vsop87MoonGeocentric(J2000);
113
+ assert.equal(mars.x.unit, 'AstronomicalUnit');
114
+ assert.equal(moon.x.unit, 'Kilometer');
115
+ assert.equal(mars.frame, 'EclipticMeanJ2000');
116
+ });
117
+
118
+ it('preserves input length units in center transforms', () => {
119
+ const transformed = transformPositionCenter(
120
+ AU(1),
121
+ AU(0),
122
+ AU(0),
123
+ 'Heliocentric',
124
+ 'Geocentric',
125
+ J2000,
126
+ );
127
+
128
+ assert.equal(transformed.x.unit, 'AstronomicalUnit');
129
+ assert.equal(transformed.y.unit, 'AstronomicalUnit');
130
+ assert.equal(transformed.z.unit, 'AstronomicalUnit');
131
+ });
132
+
133
+ it('returns typed direction values', () => {
134
+ const direction = transformDirection(
135
+ DEG(38.78),
136
+ DEG(279.23),
137
+ 'EquatorialMeanJ2000',
138
+ 'EclipticMeanJ2000',
139
+ J2000,
140
+ );
141
+
142
+ const horizontal = directionToHorizontal(
143
+ DEG(38.78),
144
+ DEG(279.23),
145
+ 'ICRS',
146
+ J2000,
147
+ Observer.roqueDeLasMuchachos(),
148
+ );
149
+
150
+ assert.equal(direction.polar.unit, 'Degree');
151
+ assert.equal(direction.azimuth.unit, 'Degree');
152
+ assert.equal(horizontal.polar.unit, 'Degree');
153
+ assert.equal(horizontal.azimuth.unit, 'Degree');
154
+ });
155
+
156
+ it('returns typed scalar astronomy values', () => {
157
+ const separation = angularSeparation(DEG(10), DEG(20), DEG(11), DEG(21), 'ICRS');
158
+ const period = orbitalPeriod('Mars');
159
+ const unitVector = directionToCartesian(DEG(45), DEG(90));
160
+
161
+ assert.equal(separation.unit, 'Degree');
162
+ assert.equal(period.unit, 'Day');
163
+ assert.equal(typeof unitVector.x, 'number');
164
+ assert.equal(typeof unitVector.y, 'number');
165
+ assert.equal(typeof unitVector.z, 'number');
166
+ });
167
+ });
168
+
169
+ describe('event APIs', () => {
170
+ it('return typed instantaneous quantities', () => {
171
+ const observer = Observer.roqueDeLasMuchachos();
172
+ const star = Star.catalog('Vega');
173
+
174
+ const bodyAltitude = bodyAltitudeAt('Sun', observer, MJD_60000);
175
+ const stellarAltitude = starAltitudeAt(star, observer, MJD_60000);
176
+
177
+ assert.equal(bodyAltitude.unit, 'Degree');
178
+ assert.equal(stellarAltitude.unit, 'Degree');
179
+ });
180
+
181
+ it('return typed event timestamps and periods', () => {
182
+ const observer = Observer.roqueDeLasMuchachos();
183
+
184
+ const crossings = bodyCrossings('Sun', observer, WINDOW, DEG(0));
185
+ const culminations = bodyCulminations('Sun', observer, WINDOW);
186
+ const darkMoon = moonIlluminationAbove(WINDOW, 0.5);
187
+ const phaseEvents = findPhaseEvents(WINDOW);
188
+
189
+ for (const event of crossings) {
190
+ assert.ok(event.mjd instanceof ModifiedJulianDate);
191
+ }
192
+ for (const event of culminations) {
193
+ assert.ok(event.mjd instanceof ModifiedJulianDate);
194
+ assert.equal(event.altitude.unit, 'Degree');
195
+ }
196
+ for (const period of darkMoon) {
197
+ assert.ok(period instanceof Period);
198
+ }
199
+ for (const event of phaseEvents) {
200
+ assert.ok(event.mjd instanceof ModifiedJulianDate);
201
+ }
202
+ });
203
+
204
+ it('intersects typed periods', () => {
205
+ const periods = intersectPeriods(
206
+ [new Period(new ModifiedJulianDate(60_000.0), new ModifiedJulianDate(60_001.0))],
207
+ [new Period(new ModifiedJulianDate(60_000.5), new ModifiedJulianDate(60_001.5))],
208
+ );
209
+
210
+ assert.equal(periods.length, 1);
211
+ assert.ok(periods[0] instanceof Period);
212
+ assert.equal(periods[0].start.value, 60_000.5);
213
+ });
214
+ });
215
+
216
+ describe('moonPhase()', () => {
217
+ it('returns typed angular values', () => {
218
+ const phase = moonPhase(J2000);
219
+ assert.equal(phase.phaseAngle.unit, 'Degree');
220
+ assert.equal(phase.elongation.unit, 'Degree');
221
+ assert.equal(typeof phase.illuminatedFraction, 'number');
222
+ });
223
+ });
224
+
225
+ describe('strict boundary validation', () => {
226
+ it('rejects raw numbers for time and angle inputs', () => {
227
+ const observer = Observer.roqueDeLasMuchachos();
228
+
229
+ assert.throws(() => vsop87Heliocentric('Mars', 2_451_545.0), /Expected a JulianDate/);
230
+ assert.throws(() => bodyAltitudeAt('Sun', observer, 60_000.0), /Expected a ModifiedJulianDate/);
231
+ assert.throws(() => bodyCrossings('Sun', observer, MJD_60000, DEG(0)), /Expected a Period/);
232
+ assert.throws(
233
+ () => transformDirection(38.78, DEG(279.23), 'ICRS', 'ICRS', J2000),
234
+ /expected a Quantity/,
235
+ );
236
+ });
237
+
238
+ it('rejects structural impostors', () => {
239
+ assert.throws(
240
+ () => new Observer({ value: 1, unit: 'Degree' }, DEG(0), M(0)),
241
+ /expected a Quantity/,
242
+ );
243
+ assert.throws(
244
+ () => bodyAltitudeAt('Sun', Observer.roqueDeLasMuchachos(), { value: 60_000 }),
245
+ /Expected a ModifiedJulianDate/,
246
+ );
247
+ });
248
+ });
@@ -0,0 +1,5 @@
1
+ extern crate napi_build;
2
+
3
+ fn main() {
4
+ napi_build::setup();
5
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "reporter": ["text-summary", "lcov", "cobertura", "html"]
3
+ }
@@ -0,0 +1,31 @@
1
+ const js = require('@eslint/js');
2
+ const globals = require('globals');
3
+
4
+ const baseRules = {
5
+ ...js.configs.recommended.rules,
6
+ 'no-console': 'off',
7
+ };
8
+
9
+ module.exports = [
10
+ {
11
+ ignores: ['coverage/**', 'node_modules/**', 'target/**', '*.d.ts', '*.node', 'index.js'],
12
+ },
13
+ {
14
+ files: ['**/*.js'],
15
+ languageOptions: {
16
+ ecmaVersion: 'latest',
17
+ sourceType: 'commonjs',
18
+ globals: globals.node,
19
+ },
20
+ rules: baseRules,
21
+ },
22
+ {
23
+ files: ['**/*.mjs'],
24
+ languageOptions: {
25
+ ecmaVersion: 'latest',
26
+ sourceType: 'module',
27
+ globals: globals.node,
28
+ },
29
+ rules: baseRules,
30
+ },
31
+ ];
@@ -0,0 +1,24 @@
1
+ import { createRequire } from 'node:module';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, join } from 'node:path';
4
+
5
+ import { Quantity } from '@siderust/qtty';
6
+ import { JulianDate } from '@siderust/tempoch';
7
+
8
+ const require = createRequire(import.meta.url);
9
+ const { Observer, directionToCartesian, geodeticToEcef, transformDirection } = require(
10
+ join(dirname(fileURLToPath(import.meta.url)), '..', 'index.js'),
11
+ );
12
+
13
+ const DEG = (value) => new Quantity(value, 'Degree');
14
+ const jd = new JulianDate(2_451_545.0);
15
+ const observer = new Observer(DEG(-17.8925), DEG(28.7543), new Quantity(2396, 'Meter'));
16
+
17
+ console.log('Observer:', observer.format());
18
+ console.log('ECEF:', geodeticToEcef(observer));
19
+
20
+ const vega = transformDirection(DEG(38.7837), DEG(279.2347), 'ICRS', 'EclipticMeanJ2000', jd);
21
+ console.log('Vega in ecliptic coordinates:', vega);
22
+
23
+ const unitVector = directionToCartesian(DEG(38.7837), DEG(279.2347));
24
+ console.log('Unit vector:', unitVector);
@@ -0,0 +1,25 @@
1
+ import { createRequire } from 'node:module';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, join } from 'node:path';
4
+
5
+ import { Quantity } from '@siderust/qtty';
6
+ import { JulianDate } from '@siderust/tempoch';
7
+
8
+ const require = createRequire(import.meta.url);
9
+ const { transformPositionCenter, transformPositionFrame, vsop87Heliocentric } = require(
10
+ join(dirname(fileURLToPath(import.meta.url)), '..', 'index.js'),
11
+ );
12
+
13
+ const jd = new JulianDate(2_451_545.0);
14
+ const mars = vsop87Heliocentric('Mars', jd);
15
+
16
+ console.log('Mars heliocentric position:', mars);
17
+ console.log(
18
+ 'Mars geocentric position:',
19
+ transformPositionCenter(mars.x, mars.y, mars.z, 'Heliocentric', 'Geocentric', jd),
20
+ );
21
+ console.log(
22
+ 'Mars equatorial position:',
23
+ transformPositionFrame(mars.x, mars.y, mars.z, 'EclipticMeanJ2000', 'EquatorialMeanJ2000', jd),
24
+ );
25
+ console.log('Reference length unit:', new Quantity(1, mars.x.unit).toString());
@@ -0,0 +1,26 @@
1
+ import { createRequire } from 'node:module';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, join } from 'node:path';
4
+
5
+ import { Quantity } from '@siderust/qtty';
6
+ import { JulianDate } from '@siderust/tempoch';
7
+
8
+ const require = createRequire(import.meta.url);
9
+ const { transformDirection } = require(
10
+ join(dirname(fileURLToPath(import.meta.url)), '..', 'index.js'),
11
+ );
12
+
13
+ const DEG = (value) => new Quantity(value, 'Degree');
14
+ const jd = new JulianDate(2_451_545.0);
15
+ const frames = [
16
+ 'ICRS',
17
+ 'EclipticMeanJ2000',
18
+ 'EquatorialMeanJ2000',
19
+ 'EquatorialMeanOfDate',
20
+ 'EquatorialTrueOfDate',
21
+ ];
22
+
23
+ for (const frame of frames) {
24
+ const result = transformDirection(DEG(38.7837), DEG(279.2347), 'ICRS', frame, jd);
25
+ console.log(frame, result);
26
+ }
@@ -0,0 +1,24 @@
1
+ import { createRequire } from 'node:module';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, join } from 'node:path';
4
+
5
+ import { JulianDate } from '@siderust/tempoch';
6
+
7
+ const require = createRequire(import.meta.url);
8
+ const { transformPositionCenter, vsop87Barycentric, vsop87EarthBarycentric } = require(
9
+ join(dirname(fileURLToPath(import.meta.url)), '..', 'index.js'),
10
+ );
11
+
12
+ const jd = new JulianDate(2_451_545.0);
13
+ const mars = vsop87Barycentric('Mars', jd);
14
+ const earth = vsop87EarthBarycentric(jd);
15
+
16
+ console.log('Mars barycentric:', mars);
17
+ console.log(
18
+ 'Mars geocentric:',
19
+ transformPositionCenter(mars.x, mars.y, mars.z, 'Barycentric', 'Geocentric', jd),
20
+ );
21
+ console.log(
22
+ 'Earth heliocentric:',
23
+ transformPositionCenter(earth.x, earth.y, earth.z, 'Barycentric', 'Heliocentric', jd),
24
+ );
@@ -0,0 +1,22 @@
1
+ import { createRequire } from 'node:module';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, join } from 'node:path';
4
+
5
+ import { Quantity } from '@siderust/qtty';
6
+ import { JulianDate } from '@siderust/tempoch';
7
+
8
+ const require = createRequire(import.meta.url);
9
+ const { transformDirection, vsop87Heliocentric } = require(
10
+ join(dirname(fileURLToPath(import.meta.url)), '..', 'index.js'),
11
+ );
12
+
13
+ const DEG = (value) => new Quantity(value, 'Degree');
14
+ const jd0 = new JulianDate(2_451_545.0);
15
+ const jd1 = new JulianDate(2_451_545.5);
16
+
17
+ console.log('Mars at J2000:', vsop87Heliocentric('Mars', jd0));
18
+ console.log('Mars 12h later:', vsop87Heliocentric('Mars', jd1));
19
+ console.log(
20
+ 'Vega of-date direction at J2000+12h:',
21
+ transformDirection(DEG(38.7837), DEG(279.2347), 'ICRS', 'EquatorialTrueOfDate', jd1),
22
+ );
@@ -0,0 +1,18 @@
1
+ import { createRequire } from 'node:module';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, join } from 'node:path';
4
+
5
+ import { Quantity } from '@siderust/qtty';
6
+ import { ModifiedJulianDate, Period } from '@siderust/tempoch';
7
+
8
+ const require = createRequire(import.meta.url);
9
+ const { Observer, bodyBelowThreshold, bodyCrossings } = require(
10
+ join(dirname(fileURLToPath(import.meta.url)), '..', 'index.js'),
11
+ );
12
+
13
+ const DEG = (value) => new Quantity(value, 'Degree');
14
+ const observer = new Observer(DEG(0), DEG(51.4769), new Quantity(0, 'Meter'));
15
+ const week = new Period(new ModifiedJulianDate(60_000.0), new ModifiedJulianDate(60_007.0));
16
+
17
+ console.log('Sunset/sunrise events:', bodyCrossings('Sun', observer, week, DEG(0)));
18
+ console.log('Astronomical night periods:', bodyBelowThreshold('Sun', observer, week, DEG(-18)));
@@ -0,0 +1,21 @@
1
+ import { createRequire } from 'node:module';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, join } from 'node:path';
4
+
5
+ import { Quantity } from '@siderust/qtty';
6
+ import { JulianDate } from '@siderust/tempoch';
7
+
8
+ const require = createRequire(import.meta.url);
9
+ const { Observer, moonPhase, moonPhaseTopocentric } = require(
10
+ join(dirname(fileURLToPath(import.meta.url)), '..', 'index.js'),
11
+ );
12
+
13
+ const observer = new Observer(
14
+ new Quantity(-17.8925, 'Degree'),
15
+ new Quantity(28.7543, 'Degree'),
16
+ new Quantity(2396, 'Meter'),
17
+ );
18
+ const jd = new JulianDate(2_451_545.0);
19
+
20
+ console.log('Geocentric moon phase:', moonPhase(jd));
21
+ console.log('Topocentric moon phase:', moonPhaseTopocentric(jd, observer));
@@ -0,0 +1,19 @@
1
+ import { createRequire } from 'node:module';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, join } from 'node:path';
4
+
5
+ import { JulianDate } from '@siderust/tempoch';
6
+
7
+ const require = createRequire(import.meta.url);
8
+ const { getPlanet, orbitalPeriod, vsop87Heliocentric } = require(
9
+ join(dirname(fileURLToPath(import.meta.url)), '..', 'index.js'),
10
+ );
11
+
12
+ const jd = new JulianDate(2_451_545.0);
13
+ for (const body of ['Mercury', 'Venus', 'Earth', 'Mars']) {
14
+ console.log(body, {
15
+ info: getPlanet(body),
16
+ period: orbitalPeriod(body),
17
+ position: vsop87Heliocentric(body, jd),
18
+ });
19
+ }
@@ -0,0 +1,22 @@
1
+ import { createRequire } from 'node:module';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, join } from 'node:path';
4
+
5
+ import { Quantity } from '@siderust/qtty';
6
+ import { ModifiedJulianDate, Period } from '@siderust/tempoch';
7
+
8
+ const require = createRequire(import.meta.url);
9
+ const { Observer, Star, intersectPeriods, starAboveThreshold, starAzimuthCrossings } = require(
10
+ join(dirname(fileURLToPath(import.meta.url)), '..', 'index.js'),
11
+ );
12
+
13
+ const observer = Observer.roqueDeLasMuchachos();
14
+ const sirius = Star.catalog('Sirius');
15
+ const window = new Period(new ModifiedJulianDate(60_000.0), new ModifiedJulianDate(60_001.0));
16
+
17
+ const highAltitude = starAboveThreshold(sirius, observer, window, new Quantity(25, 'Degree'));
18
+ const dueSouth = starAzimuthCrossings(sirius, observer, window, new Quantity(180, 'Degree'));
19
+
20
+ console.log('High-altitude periods:', highAltitude);
21
+ console.log('South crossings:', dueSouth);
22
+ console.log('Self-intersection check:', intersectPeriods(highAltitude, highAltitude));
@@ -0,0 +1,9 @@
1
+ import { ModifiedJulianDate, Period } from '@siderust/tempoch';
2
+
3
+ const window = new Period(new ModifiedJulianDate(51_544.5), new ModifiedJulianDate(51_545.5));
4
+ const later = new ModifiedJulianDate(51_545.0);
5
+
6
+ console.log('Window:', window.format());
7
+ console.log('Duration:', window.duration().toString());
8
+ console.log('Contains 51545.0:', window.contains(later));
9
+ console.log('UTC bounds:', window.toUtc());