mihrab-methods 0.0.0-stage → 1.0.1

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 (217) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +319 -2
  3. package/certification.json +120 -0
  4. package/data/corrections/algeria.json +784 -0
  5. package/data/corrections/diyanet.json +18444 -0
  6. package/data/corrections/indonesia.json +210 -0
  7. package/data/corrections/morocco.json +993 -0
  8. package/data/corrections/sweden.json +516 -0
  9. package/dist/cjs/algeria.d.ts +4 -0
  10. package/dist/cjs/algeria.js +22 -0
  11. package/dist/cjs/authorities/algeria.d.ts +3 -0
  12. package/dist/cjs/authorities/algeria.js +57 -0
  13. package/dist/cjs/authorities/diyanet.d.ts +9 -0
  14. package/dist/cjs/authorities/diyanet.js +90 -0
  15. package/dist/cjs/authorities/indonesia.d.ts +4 -0
  16. package/dist/cjs/authorities/indonesia.js +82 -0
  17. package/dist/cjs/authorities/morocco.d.ts +5 -0
  18. package/dist/cjs/authorities/morocco.js +65 -0
  19. package/dist/cjs/authorities/slug.d.ts +2 -0
  20. package/dist/cjs/authorities/slug.js +17 -0
  21. package/dist/cjs/authorities/sweden.d.ts +3 -0
  22. package/dist/cjs/authorities/sweden.js +58 -0
  23. package/dist/cjs/core/api.d.ts +61 -0
  24. package/dist/cjs/core/api.js +177 -0
  25. package/dist/cjs/core/civilDate.d.ts +17 -0
  26. package/dist/cjs/core/civilDate.js +41 -0
  27. package/dist/cjs/core/clock.d.ts +22 -0
  28. package/dist/cjs/core/clock.js +67 -0
  29. package/dist/cjs/core/compute.d.ts +10 -0
  30. package/dist/cjs/core/compute.js +59 -0
  31. package/dist/cjs/core/correctionList.d.ts +25 -0
  32. package/dist/cjs/core/correctionList.js +62 -0
  33. package/dist/cjs/core/fetchLatest.d.ts +61 -0
  34. package/dist/cjs/core/fetchLatest.js +192 -0
  35. package/dist/cjs/core/index.d.ts +14 -0
  36. package/dist/cjs/core/index.js +45 -0
  37. package/dist/cjs/core/registry.d.ts +28 -0
  38. package/dist/cjs/core/registry.js +34 -0
  39. package/dist/cjs/core/types.d.ts +193 -0
  40. package/dist/cjs/core/types.js +22 -0
  41. package/dist/cjs/core.d.ts +2 -0
  42. package/dist/cjs/core.js +18 -0
  43. package/dist/cjs/data/generated/algeriaCertification.d.ts +3 -0
  44. package/dist/cjs/data/generated/algeriaCertification.js +4 -0
  45. package/dist/cjs/data/generated/algeriaCities.d.ts +8 -0
  46. package/dist/cjs/data/generated/algeriaCities.js +5 -0
  47. package/dist/cjs/data/generated/algeriaCorrections.d.ts +3 -0
  48. package/dist/cjs/data/generated/algeriaCorrections.js +4 -0
  49. package/dist/cjs/data/generated/algeriaMethodPoints.d.ts +2 -0
  50. package/dist/cjs/data/generated/algeriaMethodPoints.js +5 -0
  51. package/dist/cjs/data/generated/countryOutlines.d.ts +5 -0
  52. package/dist/cjs/data/generated/countryOutlines.js +5 -0
  53. package/dist/cjs/data/generated/diyanetCertification.d.ts +3 -0
  54. package/dist/cjs/data/generated/diyanetCertification.js +4 -0
  55. package/dist/cjs/data/generated/diyanetCorrections.d.ts +3 -0
  56. package/dist/cjs/data/generated/diyanetCorrections.js +4 -0
  57. package/dist/cjs/data/generated/diyanetCountries.d.ts +5 -0
  58. package/dist/cjs/data/generated/diyanetCountries.js +5 -0
  59. package/dist/cjs/data/generated/diyanetTurkeyPoints.d.ts +7 -0
  60. package/dist/cjs/data/generated/diyanetTurkeyPoints.js +5 -0
  61. package/dist/cjs/data/generated/diyanetWorldPoints.d.ts +10 -0
  62. package/dist/cjs/data/generated/diyanetWorldPoints.js +5 -0
  63. package/dist/cjs/data/generated/indonesiaCertification.d.ts +3 -0
  64. package/dist/cjs/data/generated/indonesiaCertification.js +4 -0
  65. package/dist/cjs/data/generated/indonesiaCorrections.d.ts +3 -0
  66. package/dist/cjs/data/generated/indonesiaCorrections.js +4 -0
  67. package/dist/cjs/data/generated/kemenagMethodPoints.d.ts +2 -0
  68. package/dist/cjs/data/generated/kemenagMethodPoints.js +5 -0
  69. package/dist/cjs/data/generated/kemenagPlaces.d.ts +8 -0
  70. package/dist/cjs/data/generated/kemenagPlaces.js +5 -0
  71. package/dist/cjs/data/generated/moroccoCertification.d.ts +3 -0
  72. package/dist/cjs/data/generated/moroccoCertification.js +4 -0
  73. package/dist/cjs/data/generated/moroccoCities.d.ts +8 -0
  74. package/dist/cjs/data/generated/moroccoCities.js +5 -0
  75. package/dist/cjs/data/generated/moroccoCorrections.d.ts +3 -0
  76. package/dist/cjs/data/generated/moroccoCorrections.js +4 -0
  77. package/dist/cjs/data/generated/moroccoMethodPoints.d.ts +2 -0
  78. package/dist/cjs/data/generated/moroccoMethodPoints.js +5 -0
  79. package/dist/cjs/data/generated/swedenCertification.d.ts +3 -0
  80. package/dist/cjs/data/generated/swedenCertification.js +4 -0
  81. package/dist/cjs/data/generated/swedenCorrections.d.ts +3 -0
  82. package/dist/cjs/data/generated/swedenCorrections.js +4 -0
  83. package/dist/cjs/data/generated/swedenPlaces.d.ts +5 -0
  84. package/dist/cjs/data/generated/swedenPlaces.js +5 -0
  85. package/dist/cjs/diyanet.d.ts +4 -0
  86. package/dist/cjs/diyanet.js +22 -0
  87. package/dist/cjs/index.d.ts +19 -0
  88. package/dist/cjs/index.js +37 -0
  89. package/dist/cjs/indonesia.d.ts +4 -0
  90. package/dist/cjs/indonesia.js +22 -0
  91. package/dist/cjs/locate.d.ts +21 -0
  92. package/dist/cjs/locate.js +204 -0
  93. package/dist/cjs/methods/algeria.d.ts +56 -0
  94. package/dist/cjs/methods/algeria.js +119 -0
  95. package/dist/cjs/methods/indonesia.d.ts +31 -0
  96. package/dist/cjs/methods/indonesia.js +94 -0
  97. package/dist/cjs/methods/morocco.d.ts +61 -0
  98. package/dist/cjs/methods/morocco.js +113 -0
  99. package/dist/cjs/methods/revisions.d.ts +15 -0
  100. package/dist/cjs/methods/revisions.js +18 -0
  101. package/dist/cjs/methods/scratch-congress.d.ts +87 -0
  102. package/dist/cjs/methods/scratch-congress.js +539 -0
  103. package/dist/cjs/methods/sweden.d.ts +88 -0
  104. package/dist/cjs/methods/sweden.js +568 -0
  105. package/dist/cjs/morocco.d.ts +4 -0
  106. package/dist/cjs/morocco.js +22 -0
  107. package/dist/cjs/sun/preciseSun.d.ts +19 -0
  108. package/dist/cjs/sun/preciseSun.js +185 -0
  109. package/dist/cjs/sweden.d.ts +4 -0
  110. package/dist/cjs/sweden.js +22 -0
  111. package/dist/esm/algeria.d.ts +4 -0
  112. package/dist/esm/algeria.js +4 -0
  113. package/dist/esm/authorities/algeria.d.ts +3 -0
  114. package/dist/esm/authorities/algeria.js +51 -0
  115. package/dist/esm/authorities/diyanet.d.ts +9 -0
  116. package/dist/esm/authorities/diyanet.js +83 -0
  117. package/dist/esm/authorities/indonesia.d.ts +4 -0
  118. package/dist/esm/authorities/indonesia.js +75 -0
  119. package/dist/esm/authorities/morocco.d.ts +5 -0
  120. package/dist/esm/authorities/morocco.js +59 -0
  121. package/dist/esm/authorities/slug.d.ts +2 -0
  122. package/dist/esm/authorities/slug.js +14 -0
  123. package/dist/esm/authorities/sweden.d.ts +3 -0
  124. package/dist/esm/authorities/sweden.js +52 -0
  125. package/dist/esm/core/api.d.ts +61 -0
  126. package/dist/esm/core/api.js +163 -0
  127. package/dist/esm/core/civilDate.d.ts +17 -0
  128. package/dist/esm/core/civilDate.js +36 -0
  129. package/dist/esm/core/clock.d.ts +22 -0
  130. package/dist/esm/core/clock.js +60 -0
  131. package/dist/esm/core/compute.d.ts +10 -0
  132. package/dist/esm/core/compute.js +56 -0
  133. package/dist/esm/core/correctionList.d.ts +25 -0
  134. package/dist/esm/core/correctionList.js +56 -0
  135. package/dist/esm/core/fetchLatest.d.ts +61 -0
  136. package/dist/esm/core/fetchLatest.js +184 -0
  137. package/dist/esm/core/index.d.ts +14 -0
  138. package/dist/esm/core/index.js +14 -0
  139. package/dist/esm/core/registry.d.ts +28 -0
  140. package/dist/esm/core/registry.js +28 -0
  141. package/dist/esm/core/types.d.ts +193 -0
  142. package/dist/esm/core/types.js +18 -0
  143. package/dist/esm/core.d.ts +2 -0
  144. package/dist/esm/core.js +2 -0
  145. package/dist/esm/data/generated/algeriaCertification.d.ts +3 -0
  146. package/dist/esm/data/generated/algeriaCertification.js +2 -0
  147. package/dist/esm/data/generated/algeriaCities.d.ts +8 -0
  148. package/dist/esm/data/generated/algeriaCities.js +3 -0
  149. package/dist/esm/data/generated/algeriaCorrections.d.ts +3 -0
  150. package/dist/esm/data/generated/algeriaCorrections.js +2 -0
  151. package/dist/esm/data/generated/algeriaMethodPoints.d.ts +2 -0
  152. package/dist/esm/data/generated/algeriaMethodPoints.js +3 -0
  153. package/dist/esm/data/generated/countryOutlines.d.ts +5 -0
  154. package/dist/esm/data/generated/countryOutlines.js +3 -0
  155. package/dist/esm/data/generated/diyanetCertification.d.ts +3 -0
  156. package/dist/esm/data/generated/diyanetCertification.js +2 -0
  157. package/dist/esm/data/generated/diyanetCorrections.d.ts +3 -0
  158. package/dist/esm/data/generated/diyanetCorrections.js +2 -0
  159. package/dist/esm/data/generated/diyanetCountries.d.ts +5 -0
  160. package/dist/esm/data/generated/diyanetCountries.js +3 -0
  161. package/dist/esm/data/generated/diyanetTurkeyPoints.d.ts +7 -0
  162. package/dist/esm/data/generated/diyanetTurkeyPoints.js +3 -0
  163. package/dist/esm/data/generated/diyanetWorldPoints.d.ts +10 -0
  164. package/dist/esm/data/generated/diyanetWorldPoints.js +3 -0
  165. package/dist/esm/data/generated/indonesiaCertification.d.ts +3 -0
  166. package/dist/esm/data/generated/indonesiaCertification.js +2 -0
  167. package/dist/esm/data/generated/indonesiaCorrections.d.ts +3 -0
  168. package/dist/esm/data/generated/indonesiaCorrections.js +2 -0
  169. package/dist/esm/data/generated/kemenagMethodPoints.d.ts +2 -0
  170. package/dist/esm/data/generated/kemenagMethodPoints.js +3 -0
  171. package/dist/esm/data/generated/kemenagPlaces.d.ts +8 -0
  172. package/dist/esm/data/generated/kemenagPlaces.js +3 -0
  173. package/dist/esm/data/generated/moroccoCertification.d.ts +3 -0
  174. package/dist/esm/data/generated/moroccoCertification.js +2 -0
  175. package/dist/esm/data/generated/moroccoCities.d.ts +8 -0
  176. package/dist/esm/data/generated/moroccoCities.js +3 -0
  177. package/dist/esm/data/generated/moroccoCorrections.d.ts +3 -0
  178. package/dist/esm/data/generated/moroccoCorrections.js +2 -0
  179. package/dist/esm/data/generated/moroccoMethodPoints.d.ts +2 -0
  180. package/dist/esm/data/generated/moroccoMethodPoints.js +3 -0
  181. package/dist/esm/data/generated/swedenCertification.d.ts +3 -0
  182. package/dist/esm/data/generated/swedenCertification.js +2 -0
  183. package/dist/esm/data/generated/swedenCorrections.d.ts +3 -0
  184. package/dist/esm/data/generated/swedenCorrections.js +2 -0
  185. package/dist/esm/data/generated/swedenPlaces.d.ts +5 -0
  186. package/dist/esm/data/generated/swedenPlaces.js +3 -0
  187. package/dist/esm/diyanet.d.ts +4 -0
  188. package/dist/esm/diyanet.js +4 -0
  189. package/dist/esm/index.d.ts +19 -0
  190. package/dist/esm/index.js +19 -0
  191. package/dist/esm/indonesia.d.ts +4 -0
  192. package/dist/esm/indonesia.js +4 -0
  193. package/dist/esm/locate.d.ts +21 -0
  194. package/dist/esm/locate.js +196 -0
  195. package/dist/esm/methods/algeria.d.ts +56 -0
  196. package/dist/esm/methods/algeria.js +114 -0
  197. package/dist/esm/methods/indonesia.d.ts +31 -0
  198. package/dist/esm/methods/indonesia.js +90 -0
  199. package/dist/esm/methods/morocco.d.ts +61 -0
  200. package/dist/esm/methods/morocco.js +107 -0
  201. package/dist/esm/methods/revisions.d.ts +15 -0
  202. package/dist/esm/methods/revisions.js +15 -0
  203. package/dist/esm/methods/scratch-congress.d.ts +87 -0
  204. package/dist/esm/methods/scratch-congress.js +534 -0
  205. package/dist/esm/methods/sweden.d.ts +88 -0
  206. package/dist/esm/methods/sweden.js +563 -0
  207. package/dist/esm/morocco.d.ts +4 -0
  208. package/dist/esm/morocco.js +4 -0
  209. package/dist/esm/package.json +1 -0
  210. package/dist/esm/sun/preciseSun.d.ts +19 -0
  211. package/dist/esm/sun/preciseSun.js +181 -0
  212. package/dist/esm/sweden.d.ts +4 -0
  213. package/dist/esm/sweden.js +4 -0
  214. package/docs/methods.md +190 -0
  215. package/package.json +178 -4
  216. package/schemas/certification.schema.json +59 -0
  217. package/schemas/corrections.schema.json +29 -0
@@ -0,0 +1,2 @@
1
+ const data = { "from": "2024-01-01", "to": "2027-12-31", "points": { "55.376,13.159": ["2027-01-27 maghrib +1"], "55.417,12.844": ["2025-05-04 sunrise -1", "2026-06-14 isha -1", "2027-02-04 sunrise +1"], "55.430,13.136": ["2024-04-26 sunrise -1"], "55.483,13.507": ["2027-12-26 asr -1"], "55.513,13.234": ["2024-08-30 maghrib +1", "2025-08-18 maghrib +1", "2027-11-10 asr +1"], "55.535,14.325": ["2026-12-22 maghrib -1", "2027-04-12 isha +1", "2027-04-15 isha +1", "2027-04-16 isha +1", "2027-04-17 isha +1", "2027-04-20 isha +1", "2027-04-21 isha +1", "2027-04-25 isha +1", "2027-04-30 isha +1"], "55.556,14.337": ["2024-03-20 sunrise +1", "2024-05-14 maghrib +1"], "55.673,13.074": ["2024-07-25 isha +1", "2026-06-24 isha -1", "2027-01-10 asr -1", "2027-01-25 asr +1", "2027-11-17 sunrise -1"], "55.713,13.186": ["2024-02-15 isha +1"], "55.718,13.021": ["2025-04-22 fajr +1", "2025-05-05 fajr +1", "2027-09-20 fajr -1"], "55.777,13.087": ["2026-10-27 maghrib +1"], "55.800,13.661": ["2027-02-09 sunrise -1"], "55.837,13.296": ["2026-05-02 fajr +1"], "55.878,12.832": ["2024-12-29 sunrise +1", "2025-04-30 sunrise -1"], "55.931,13.541": ["2025-07-31 fajr +1"], "56.030,14.158": ["2025-01-01 fajr +1"], "56.048,14.576": ["2025-07-22 sunrise -1", "2025-12-10 asr +1"], "56.156,13.762": ["2024-08-14 maghrib +1", "2025-06-18 fajr +1"], "56.175,15.587": ["2024-11-04 maghrib +1", "2026-08-16 asr +1"], "56.199,12.549": ["2026-07-25 sunrise -1"], "56.206,15.279": ["2027-03-21 isha -1", "2027-05-02 fajr -1"], "56.244,12.872": ["2024-06-06 maghrib +1"], "56.520,13.044": ["2025-03-28 asr -1", "2025-07-20 isha -1"], "56.668,16.353": ["2024-01-06 sunrise +1"], "56.750,15.260": ["2025-06-09 isha -1"], "56.750,15.894": ["2025-08-11 asr +1", "2026-11-20 isha +1", "2027-05-10 sunrise -1"], "56.835,13.939": ["2025-05-13 isha -1", "2025-06-02 fajr +1"], "56.884,14.803": ["2027-12-10 isha +1"], "57.033,16.444": ["2027-09-07 maghrib +1"], "57.106,12.254": ["2024-06-12 fajr +1", "2024-07-31 fajr +1", "2025-12-07 asr -1"], "57.167,16.027": ["2026-11-13 asr +1", "2026-12-26 sunrise +1"], "57.180,14.052": ["2026-09-11 isha +1"], "57.264,16.456": ["2025-12-23 maghrib -1"], "57.301,13.525": ["2024-07-12 fajr +1"], "57.345,12.133": ["2026-10-10 maghrib +1"], "57.368,13.726": ["2024-04-07 fajr +1", "2024-04-13 fajr +1", "2024-04-19 fajr +1", "2024-04-25 fajr +1", "2025-08-15 maghrib +1"], "57.401,14.668": ["2024-07-20 fajr +1"], "57.426,15.079": ["2024-06-28 isha -1", "2027-06-04 sunrise -1"], "57.488,13.360": ["2024-01-16 sunrise -1", "2025-07-28 maghrib +1", "2027-04-07 maghrib -1"], "57.493,12.652": ["2025-01-16 fajr +1", "2025-11-18 maghrib +1", "2026-08-15 asr +1", "2027-08-15 maghrib +1"], "57.500,15.844": ["2027-03-25 isha -1", "2027-08-03 isha +1"], "57.501,12.093": ["2026-08-09 fajr -1"], "57.635,18.292": ["2026-08-08 asr +1", "2026-11-21 maghrib +1"], "57.650,12.009": ["2025-04-28 sunrise -1", "2026-05-17 maghrib +1", "2026-05-18 maghrib +1", "2026-07-20 fajr -1"], "57.667,15.844": ["2024-03-22 fajr +1", "2025-08-18 sunrise -1", "2027-09-04 sunrise -1"], "57.678,12.609": ["2024-10-31 isha +1"], "57.689,12.225": ["2026-08-11 fajr -1", "2026-11-25 sunrise -1"], "57.695,11.652": ["2026-08-18 fajr -1", "2026-08-31 fajr -1", "2027-04-06 isha -1"], "57.720,11.994": ["2026-08-08 fajr -1", "2027-08-07 maghrib +1"], "57.733,12.110": ["2025-02-16 fajr -1"], "57.760,16.630": ["2025-06-20 asr -1"], "57.767,12.280": ["2024-11-01 maghrib +1", "2025-04-14 fajr +1", "2026-05-19 fajr -1"], "57.796,13.415": ["2025-05-03 maghrib +1", "2025-09-26 sunrise -1", "2027-04-18 sunrise +1"], "57.801,12.309": ["2024-12-31 maghrib -1", "2027-06-29 isha -1"], "58.071,11.830": ["2024-03-10 asr -1", "2024-06-22 fajr +1", "2024-08-25 isha -1"], "58.180,13.544": ["2025-10-29 asr +1", "2027-02-12 maghrib +1"], "58.322,15.136": ["2026-05-03 isha +1", "2026-09-04 sunrise -1", "2027-06-19 sunrise -1"], "58.352,11.936": ["2025-08-20 maghrib +1"], "58.369,12.329": ["2024-09-11 isha +1", "2027-12-31 sunrise +1"], "58.385,13.842": ["2024-05-15 asr +1", "2027-05-24 maghrib +1"], "58.467,11.689": ["2026-06-17 fajr -1"], "58.500,13.159": ["2024-07-28 asr +1", "2024-08-20 maghrib +1", "2024-08-31 isha +1", "2025-07-04 maghrib -1", "2027-09-10 isha +1"], "58.500,15.621": ["2026-12-02 maghrib +1", "2027-06-08 fajr +1"], "58.538,15.043": ["2026-08-08 asr +1", "2027-01-09 sunrise +1"], "58.592,16.174": ["2025-10-27 sunrise +1"], "58.675,17.130": ["2024-11-11 maghrib +1", "2025-05-13 maghrib +1", "2025-08-03 asr +1", "2026-08-12 sunrise -1", "2027-08-10 sunrise -1"], "58.700,12.461": ["2027-07-30 asr +1"], "58.711,13.827": ["2025-06-09 sunrise -1"], "58.718,15.774": ["2024-03-29 isha -1", "2025-08-21 fajr -1", "2025-09-03 fajr -1"], "58.752,17.013": ["2024-02-10 asr +1", "2025-05-11 isha +1"], "58.908,17.949": ["2025-07-29 sunrise -1", "2027-01-07 sunrise +1", "2027-05-04 fajr +1"], "58.943,11.170": ["2026-01-30 isha -1", "2026-05-30 sunrise -1", "2027-06-24 fajr +1"], "58.991,16.202": ["2026-03-06 isha -1", "2026-07-31 maghrib +1"], "59.034,12.222": ["2024-08-06 fajr -1"], "59.058,16.589": ["2026-05-22 sunrise -1"], "59.095,17.559": ["2025-06-05 fajr -1"], "59.191,17.630": ["2024-05-07 maghrib +1", "2026-10-08 maghrib +1", "2027-05-15 isha -1"], "59.268,18.191": ["2027-07-13 fajr +1", "2027-11-29 maghrib +1"], "59.277,15.211": ["2024-05-27 fajr -1", "2027-04-08 sunrise +1"], "59.317,14.115": ["2024-08-09 maghrib +1"], "59.319,18.459": ["2027-05-20 sunrise -1"], "59.330,18.034": ["2024-07-18 maghrib +1", "2024-08-05 isha +1"], "59.333,14.502": ["2024-03-24 asr -1", "2024-12-11 isha +1"], "59.375,17.018": ["2025-06-20 maghrib -1"], "59.377,17.948": ["2025-08-17 isha +1", "2026-08-13 asr +1", "2027-12-13 maghrib -1"], "59.417,17.827": ["2025-04-21 fajr -1", "2025-06-30 maghrib -1", "2026-11-29 maghrib +1", "2027-08-02 sunrise -1"], "59.514,15.989": ["2024-06-21 asr +1", "2027-08-24 sunrise -1"], "59.542,18.073": ["2026-06-05 sunrise -1", "2027-05-23 asr +1", "2027-07-26 maghrib +1"], "59.584,17.494": ["2025-08-06 isha +1"], "59.601,15.230": ["2026-03-05 fajr -1", "2027-08-12 maghrib +1"], "59.619,17.851": ["2024-05-29 fajr -1"], "59.620,16.544": ["2024-09-23 maghrib +1", "2025-08-24 maghrib +1", "2026-09-16 fajr -1"], "59.717,14.161": ["2024-07-20 isha +1"], "59.862,17.636": ["2024-07-23 isha +1", "2024-08-17 isha +1", "2024-08-18 fajr -1", "2024-09-14 maghrib +1", "2026-06-24 isha -1"], "59.926,16.589": ["2026-04-30 fajr +1", "2026-09-04 maghrib +1", "2027-07-13 sunrise -1"], "59.990,15.804": ["2027-03-13 isha -1"], "60.133,12.994": ["2026-06-07 isha +1", "2026-06-16 isha +1", "2026-06-21 isha +1", "2026-06-22 isha +1", "2026-06-23 isha +1", "2026-06-24 isha +1", "2026-06-25 isha +1", "2026-06-26 isha +1", "2026-06-27 isha +1", "2026-11-16 fajr -1"], "60.139,15.184": ["2024-04-09 sunrise +1", "2026-02-19 maghrib +1"], "60.154,16.175": ["2024-12-14 fajr +1", "2026-10-23 isha +1"], "60.609,15.628": ["2027-05-01 fajr -1", "2027-08-01 fajr -1"], "60.618,16.771": ["2026-07-23 sunrise -1"], "60.680,17.116": ["2024-12-16 sunrise +1", "2026-08-02 sunrise -1"], "61.010,14.550": ["2027-10-14 maghrib +1"], "61.349,16.390": ["2025-07-24 sunrise -1", "2027-01-06 sunrise +1"], "61.735,17.104": ["2024-07-26 maghrib +1", "2024-08-11 fajr -1", "2025-01-01 sunrise +1", "2026-08-27 fajr -1", "2026-09-02 fajr -1", "2026-09-08 fajr -1", "2026-09-14 fajr -1"], "61.833,16.091": ["2025-09-19 sunrise -1"], "62.037,14.370": ["2027-01-09 maghrib -1", "2027-08-11 isha +1"], "62.401,17.323": ["2025-11-16 sunrise -1", "2027-07-27 sunrise -1"], "62.930,17.785": ["2024-07-27 sunrise -1", "2025-08-01 fajr -1", "2025-08-30 fajr -1", "2025-09-12 fajr -1", "2026-11-23 sunrise -1"], "63.179,14.644": ["2025-04-27 isha +1", "2027-09-13 isha +1"], "63.291,18.710": ["2024-07-21 maghrib +1"], "63.834,20.238": ["2024-01-18 maghrib +1", "2026-05-02 fajr -1"], "64.751,20.945": ["2025-05-04 asr +1", "2026-08-07 fajr -1"], "65.313,21.513": ["2027-05-26 isha +1"], "65.600,22.157": ["2025-04-11 maghrib -1", "2025-09-05 maghrib +1"], "65.827,21.700": ["2024-05-03 isha +1", "2024-08-24 maghrib +1", "2025-04-26 isha +1"], "66.599,19.841": ["2024-04-21 maghrib -1", "2026-11-08 sunrise -1", "2027-05-07 isha +1"], "67.138,20.659": ["2025-08-04 maghrib +1", "2025-08-28 sunrise -1", "2026-04-25 isha +1", "2026-09-10 isha +1", "2026-09-19 isha +1", "2026-09-28 isha +1"], "67.206,23.397": ["2024-03-22 asr -1", "2025-02-14 sunrise -1"], "67.859,20.226": ["2024-08-06 isha -1", "2025-08-07 isha -1", "2025-08-18 sunrise -1", "2026-08-07 isha -1", "2027-01-30 fajr -1", "2027-09-23 maghrib +1"] } };
2
+ export default data;
@@ -0,0 +1,5 @@
1
+ declare const data: Record<string, {
2
+ lat: number;
3
+ lng: number;
4
+ }>;
5
+ export default data;
@@ -0,0 +1,3 @@
1
+ // Generated by scripts/embed.mjs — do not edit; edit the JSON under data/ instead.
2
+ const data = { "Stockholm": { "lat": 59.33, "lng": 18.034 }, "Alingsås": { "lat": 57.932, "lng": 12.538 }, "Avesta": { "lat": 60.154, "lng": 16.175 }, "Bengtsfors": { "lat": 59.034, "lng": 12.222 }, "Boden": { "lat": 65.827, "lng": 21.7 }, "Bollnäs": { "lat": 61.349, "lng": 16.39 }, "Borlänge": { "lat": 60.484, "lng": 15.439 }, "Borås": { "lat": 57.723, "lng": 12.94 }, "Eksjö": { "lat": 57.667, "lng": 14.964 }, "Enköping": { "lat": 59.645, "lng": 17.084 }, "Eskilstuna": { "lat": 59.372, "lng": 16.513 }, "Eslöv": { "lat": 55.837, "lng": 13.296 }, "Fagersta": { "lat": 59.99, "lng": 15.804 }, "Falkenberg": { "lat": 56.896, "lng": 12.503 }, "Falköping": { "lat": 58.18, "lng": 13.544 }, "Flen": { "lat": 59.058, "lng": 16.589 }, "Filipstad": { "lat": 59.717, "lng": 14.161 }, "Gislaved": { "lat": 57.301, "lng": 13.525 }, "Gnosjö": { "lat": 57.368, "lng": 13.726 }, "Gällivare": { "lat": 67.138, "lng": 20.659 }, "Gävle": { "lat": 60.68, "lng": 17.116 }, "Göteborg": { "lat": 57.72, "lng": 11.994 }, "Halmstad": { "lat": 56.666, "lng": 12.859 }, "Haparanda": { "lat": 65.848, "lng": 24.144 }, "Helsingborg": { "lat": 56.045, "lng": 12.697 }, "Hudiksvall": { "lat": 61.735, "lng": 17.104 }, "Hultsfred": { "lat": 57.5, "lng": 15.844 }, "Härnösand": { "lat": 62.638, "lng": 17.929 }, "Hässleholm": { "lat": 56.156, "lng": 13.762 }, "Högsby": { "lat": 57.167, "lng": 16.027 }, "Hörby": { "lat": 55.8, "lng": 13.661 }, "Jokkmokk": { "lat": 66.599, "lng": 19.841 }, "Jönköping": { "lat": 57.784, "lng": 14.163 }, "Kalmar": { "lat": 56.668, "lng": 16.353 }, "Karlskoga": { "lat": 59.333, "lng": 14.502 }, "Karlskrona": { "lat": 56.175, "lng": 15.587 }, "Karlstad": { "lat": 59.378, "lng": 13.498 }, "Katrineholm": { "lat": 58.991, "lng": 16.202 }, "Kiruna": { "lat": 67.859, "lng": 20.226 }, "Kristianstad": { "lat": 56.03, "lng": 14.158 }, "Kristinehamn": { "lat": 59.317, "lng": 14.115 }, "Köping": { "lat": 59.514, "lng": 15.989 }, "Laholm": { "lat": 56.52, "lng": 13.044 }, "Landskrona": { "lat": 55.878, "lng": 12.832 }, "Lessebo": { "lat": 56.75, "lng": 15.26 }, "Lidköping": { "lat": 58.5, "lng": 13.159 }, "Linköping": { "lat": 58.5, "lng": 15.621 }, "Ludvika": { "lat": 60.139, "lng": 15.184 }, "Luleå": { "lat": 65.6, "lng": 22.157 }, "Lund": { "lat": 55.713, "lng": 13.186 }, "Lysekil": { "lat": 58.275, "lng": 11.44 }, "Malmö": { "lat": 55.6, "lng": 13.004 }, "Mariestad": { "lat": 58.711, "lng": 13.827 }, "Mellerud": { "lat": 58.7, "lng": 12.461 }, "Mjölby": { "lat": 58.322, "lng": 15.136 }, "Mora": { "lat": 61.01, "lng": 14.55 }, "Munkedal": { "lat": 58.467, "lng": 11.689 }, "Mönsterås": { "lat": 57.033, "lng": 16.444 }, "Märsta": { "lat": 59.619, "lng": 17.851 }, "Norrköping": { "lat": 58.592, "lng": 16.174 }, "Norrtälje": { "lat": 59.761, "lng": 18.701 }, "Nybro": { "lat": 56.75, "lng": 15.894 }, "Nyköping": { "lat": 58.752, "lng": 17.013 }, "Nynäshamn": { "lat": 58.908, "lng": 17.949 }, "Nässjö": { "lat": 57.661, "lng": 14.704 }, "Oskarshamn": { "lat": 57.264, "lng": 16.456 }, "Oxelösund": { "lat": 58.675, "lng": 17.13 }, "Pajala": { "lat": 67.206, "lng": 23.397 }, "Piteå": { "lat": 65.313, "lng": 21.513 }, "Ronneby": { "lat": 56.206, "lng": 15.279 }, "Sala": { "lat": 59.926, "lng": 16.589 }, "Simrishamn": { "lat": 55.556, "lng": 14.337 }, "Skara": { "lat": 58.387, "lng": 13.432 }, "Skellefteå": { "lat": 64.751, "lng": 20.945 }, "Skövde": { "lat": 58.385, "lng": 13.842 }, "Sollefteå": { "lat": 63.183, "lng": 17.26 }, "Strängnäs": { "lat": 59.375, "lng": 17.018 }, "Sundsvall": { "lat": 62.401, "lng": 17.323 }, "Säffle": { "lat": 59.133, "lng": 12.924 }, "Sävsjö": { "lat": 57.401, "lng": 14.668 }, "Söderhamn": { "lat": 61.314, "lng": 17.076 }, "Södertälje": { "lat": 59.191, "lng": 17.63 }, "Sölvesborg": { "lat": 56.048, "lng": 14.576 }, "Tierp": { "lat": 60.343, "lng": 17.509 }, "Torsby": { "lat": 60.133, "lng": 12.994 }, "Tranemo": { "lat": 57.488, "lng": 13.36 }, "Tranås": { "lat": 58.037, "lng": 14.971 }, "Trelleborg": { "lat": 55.376, "lng": 13.159 }, "Trollhättan": { "lat": 58.284, "lng": 12.308 }, "Uddevalla": { "lat": 58.352, "lng": 11.936 }, "Ulricehamn": { "lat": 57.796, "lng": 13.415 }, "Umeå": { "lat": 63.834, "lng": 20.238 }, "Uppsala": { "lat": 59.862, "lng": 17.636 }, "Varberg": { "lat": 57.106, "lng": 12.254 }, "Vetlanda": { "lat": 57.426, "lng": 15.079 }, "Vimmerby": { "lat": 57.667, "lng": 15.844 }, "Visby": { "lat": 57.635, "lng": 18.292 }, "Vänersborg": { "lat": 58.369, "lng": 12.329 }, "Värnamo": { "lat": 57.18, "lng": 14.052 }, "Västervik": { "lat": 57.76, "lng": 16.63 }, "Västerås": { "lat": 59.62, "lng": 16.544 }, "Växjö": { "lat": 56.884, "lng": 14.803 }, "Ystad": { "lat": 55.43, "lng": 13.136 }, "Åmål": { "lat": 59.05, "lng": 12.694 }, "Ängelholm": { "lat": 56.244, "lng": 12.872 }, "Örebro": { "lat": 59.277, "lng": 15.211 }, "Örnsköldsvik": { "lat": 63.291, "lng": 18.71 }, "Östersund": { "lat": 63.179, "lng": 14.644 } };
3
+ export default data;
@@ -0,0 +1,4 @@
1
+ /** mihrab-methods/diyanet — the diyanet method with its places and correction list, and nothing else's. */
2
+ import './authorities/diyanet.js';
3
+ export * from './core/index.js';
4
+ export { places } from './authorities/diyanet.js';
@@ -0,0 +1,4 @@
1
+ /** mihrab-methods/diyanet — the diyanet method with its places and correction list, and nothing else's. */
2
+ import './authorities/diyanet.js';
3
+ export * from './core/index.js';
4
+ export { places } from './authorities/diyanet.js';
@@ -0,0 +1,19 @@
1
+ /**
2
+ * mihrab-methods — the prayer-time authorities' own methods, each
3
+ * reproducing its published timetable to the minute: Sweden (Diyanet's
4
+ * method, as Islamiska Förbundet prints it), Diyanet worldwide, Morocco
5
+ * (Habous), Algeria (the Ministry of Religious Affairs) and Indonesia
6
+ * (Kemenag). This entry loads all five; `mihrab-methods/<authority>` loads
7
+ * one, with only its data.
8
+ *
9
+ * import { placesOf, nearestPlace, timesFor } from 'mihrab-methods';
10
+ * const { place } = nearestPlace('algeria', 36.75, 3.06)!;
11
+ * timesFor(place, '2026-10-15');
12
+ */
13
+ import './authorities/sweden.js';
14
+ import './authorities/diyanet.js';
15
+ import './authorities/morocco.js';
16
+ import './authorities/algeria.js';
17
+ import './authorities/indonesia.js';
18
+ export * from './core/index.js';
19
+ export { diyanetCountry } from './authorities/diyanet.js';
@@ -0,0 +1,19 @@
1
+ /**
2
+ * mihrab-methods — the prayer-time authorities' own methods, each
3
+ * reproducing its published timetable to the minute: Sweden (Diyanet's
4
+ * method, as Islamiska Förbundet prints it), Diyanet worldwide, Morocco
5
+ * (Habous), Algeria (the Ministry of Religious Affairs) and Indonesia
6
+ * (Kemenag). This entry loads all five; `mihrab-methods/<authority>` loads
7
+ * one, with only its data.
8
+ *
9
+ * import { placesOf, nearestPlace, timesFor } from 'mihrab-methods';
10
+ * const { place } = nearestPlace('algeria', 36.75, 3.06)!;
11
+ * timesFor(place, '2026-10-15');
12
+ */
13
+ import './authorities/sweden.js';
14
+ import './authorities/diyanet.js';
15
+ import './authorities/morocco.js';
16
+ import './authorities/algeria.js';
17
+ import './authorities/indonesia.js';
18
+ export * from './core/index.js';
19
+ export { diyanetCountry } from './authorities/diyanet.js';
@@ -0,0 +1,4 @@
1
+ /** mihrab-methods/indonesia — the indonesia method with its places and correction list, and nothing else's. */
2
+ import './authorities/indonesia.js';
3
+ export * from './core/index.js';
4
+ export { places } from './authorities/indonesia.js';
@@ -0,0 +1,4 @@
1
+ /** mihrab-methods/indonesia — the indonesia method with its places and correction list, and nothing else's. */
2
+ import './authorities/indonesia.js';
3
+ export * from './core/index.js';
4
+ export { places } from './authorities/indonesia.js';
@@ -0,0 +1,21 @@
1
+ import type { Authority } from './core/types.js';
2
+ /** Offshore, or a coast the outline cut: the nearest country this close. */
3
+ export declare const COASTAL_REACH_KM = 25;
4
+ /**
5
+ * The country at a point (ISO 3166-1 alpha-2), among those with a method
6
+ * here and their neighbours; null elsewhere. Western Sahara answers 'MA' and
7
+ * Northern Cyprus 'TR', with the authorities that serve them. A point on no
8
+ * land — offshore, or on a coast the simplification shaved — is given to
9
+ * the nearest country within 25 km.
10
+ */
11
+ export declare function countryAt(latitude: number, longitude: number): string | null;
12
+ /**
13
+ * The authority whose table a point's community prays by: Sweden's inside
14
+ * Sweden, Morocco's in Morocco (with Western Sahara, and Ceuta and Melilla,
15
+ * which the ministry lists — when `mihrab-methods/morocco` is loaded, so
16
+ * its cities can be consulted), Algeria's, Indonesia's, and Diyanet's in
17
+ * Türkiye and Northern Cyprus. Null elsewhere: Diyanet publishes tables
18
+ * for places in 197 other countries, but it is not those countries' own
19
+ * authority, so an app offers it there as a choice, not as the default.
20
+ */
21
+ export declare function defaultAuthorityFor(latitude: number, longitude: number): Authority | null;
@@ -0,0 +1,196 @@
1
+ /**
2
+ * mihrab-methods/locate — which authority a point belongs to.
3
+ *
4
+ * `countryAt(lat, lon)` answers the country at a point among those with a
5
+ * method here and their neighbours, from Natural Earth's 1:10m outlines
6
+ * (public domain) simplified to a few hundred metres — so a border town, a
7
+ * strait or a split island is answered by the side it is on (Haparanda and
8
+ * Tornio, two kilometres apart; Ceuta on Morocco's coast; Sebatik, split
9
+ * between Indonesia and Malaysia). `defaultAuthorityFor(lat, lon)` turns
10
+ * that into the authority whose table the point's community prays by, or
11
+ * null where none of the five applies.
12
+ *
13
+ * Its own entry point because the outlines are 470 KB an app that already
14
+ * knows its country does not need.
15
+ */
16
+ import outlines from './data/generated/countryOutlines.js';
17
+ import { isLoaded } from './core/registry.js';
18
+ import { nearestPlace } from './core/api.js';
19
+ /** Offshore, or a coast the outline cut: the nearest country this close. */
20
+ export const COASTAL_REACH_KM = 25;
21
+ function ring(flat, scale) {
22
+ const n = flat.length / 2;
23
+ const xs = new Float64Array(n);
24
+ const ys = new Float64Array(n);
25
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
26
+ for (let i = 0; i < n; i++) {
27
+ const x = flat[2 * i] / scale;
28
+ const y = flat[2 * i + 1] / scale;
29
+ xs[i] = x;
30
+ ys[i] = y;
31
+ if (x < minX)
32
+ minX = x;
33
+ if (x > maxX)
34
+ maxX = x;
35
+ if (y < minY)
36
+ minY = y;
37
+ if (y > maxY)
38
+ maxY = y;
39
+ }
40
+ return { xs, ys, minX, minY, maxX, maxY };
41
+ }
42
+ let countries = null;
43
+ function load() {
44
+ if (countries)
45
+ return countries;
46
+ return (countries = Object.entries(outlines.countries).map(([code, polys]) => {
47
+ const ps = polys.map(rings => ({ outer: ring(rings[0], outlines.scale), holes: rings.slice(1).map(r => ring(r, outlines.scale)) }));
48
+ return {
49
+ code,
50
+ polys: ps,
51
+ minX: Math.min(...ps.map(p => p.outer.minX)),
52
+ minY: Math.min(...ps.map(p => p.outer.minY)),
53
+ maxX: Math.max(...ps.map(p => p.outer.maxX)),
54
+ maxY: Math.max(...ps.map(p => p.outer.maxY)),
55
+ };
56
+ }));
57
+ }
58
+ function inRing(r, x, y) {
59
+ if (x < r.minX || x > r.maxX || y < r.minY || y > r.maxY)
60
+ return false;
61
+ let hit = false;
62
+ const { xs, ys } = r;
63
+ for (let i = 0, j = xs.length - 1; i < xs.length; j = i++) {
64
+ if (ys[i] > y !== ys[j] > y && x < ((xs[j] - xs[i]) * (y - ys[i])) / (ys[j] - ys[i]) + xs[i])
65
+ hit = !hit;
66
+ }
67
+ return hit;
68
+ }
69
+ /** Distance (km) from a point to a ring's edge, on a local flat projection. */
70
+ function edgeKm(r, x, y) {
71
+ const kx = 111.32 * Math.cos((y * Math.PI) / 180);
72
+ const ky = 110.57;
73
+ let best = Infinity;
74
+ const { xs, ys } = r;
75
+ for (let i = 0, j = xs.length - 1; i < xs.length; j = i++) {
76
+ const ax = (xs[j] - x) * kx, ay = (ys[j] - y) * ky;
77
+ const bx = (xs[i] - x) * kx, by = (ys[i] - y) * ky;
78
+ const dx = bx - ax, dy = by - ay;
79
+ const len = dx * dx + dy * dy;
80
+ const t = len > 0 ? Math.max(0, Math.min(1, -(ax * dx + ay * dy) / len)) : 0;
81
+ const px = ax + t * dx, py = ay + t * dy;
82
+ const d = px * px + py * py;
83
+ if (d < best)
84
+ best = d;
85
+ }
86
+ return Math.sqrt(best);
87
+ }
88
+ /**
89
+ * Where the 1:10m outline itself is wrong by more than a town, or a town is
90
+ * closer to a border than the outlines can tell: [lat, lon, radius km,
91
+ * country]. Its Torne runs half a kilometre east of the real one, so Tornio
92
+ * was Swedish; its fell border puts Riksgränsen, the Swedish station, in
93
+ * Norway; and it has no Kastellorizo, two kilometres off Kaş.
94
+ */
95
+ const FIXES = [
96
+ [65.85, 24.17, 1.3, 'FI'], // Tornio's centre (Haparanda is across the river, 2 km west)
97
+ [68.4256, 18.1265, 1.5, 'SE'], // Riksgränsen
98
+ [36.1497, 29.5947, 3, 'GR'], // Kastellorizo
99
+ [59.3797, 28.1791, 1, 'EE'], // Narva (Ivangorod, Russia, across the river)
100
+ [38.4562, 48.875, 1.2, 'AZ'], // Astara (Astara, Iran, across the river)
101
+ [29.5577, 34.9519, 2, 'IL'], // Eilat (Aqaba 5 km east, Taba 7 km south)
102
+ ];
103
+ function fixAt(latitude, longitude) {
104
+ for (const [lat, lon, km, code] of FIXES) {
105
+ const dy = (latitude - lat) * 110.57;
106
+ const dx = (longitude - lon) * 111.32 * Math.cos((lat * Math.PI) / 180);
107
+ if (dx * dx + dy * dy <= km * km)
108
+ return code;
109
+ }
110
+ return null;
111
+ }
112
+ function nearestWithin(all, x, y, reachKm) {
113
+ const reachY = reachKm / 110;
114
+ const reachX = reachKm / (111.32 * Math.max(0.05, Math.cos((y * Math.PI) / 180)));
115
+ let best = reachKm;
116
+ let code = null;
117
+ for (const c of all) {
118
+ if (x < c.minX - reachX || x > c.maxX + reachX || y < c.minY - reachY || y > c.maxY + reachY)
119
+ continue;
120
+ for (const p of c.polys) {
121
+ const r = p.outer;
122
+ if (x < r.minX - reachX || x > r.maxX + reachX || y < r.minY - reachY || y > r.maxY + reachY)
123
+ continue;
124
+ const d = edgeKm(r, x, y);
125
+ if (d < best) {
126
+ best = d;
127
+ code = c.code;
128
+ }
129
+ }
130
+ }
131
+ return code;
132
+ }
133
+ /**
134
+ * The country at a point (ISO 3166-1 alpha-2), among those with a method
135
+ * here and their neighbours; null elsewhere. Western Sahara answers 'MA' and
136
+ * Northern Cyprus 'TR', with the authorities that serve them. A point on no
137
+ * land — offshore, or on a coast the simplification shaved — is given to
138
+ * the nearest country within 25 km.
139
+ */
140
+ export function countryAt(latitude, longitude) {
141
+ if (!Number.isFinite(latitude) || !Number.isFinite(longitude))
142
+ return null;
143
+ const fixed = fixAt(latitude, longitude);
144
+ if (fixed)
145
+ return fixed;
146
+ const x = longitude, y = latitude;
147
+ const all = load();
148
+ for (const c of all) {
149
+ if (x < c.minX || x > c.maxX || y < c.minY || y > c.maxY)
150
+ continue;
151
+ if (c.polys.some(p => inRing(p.outer, x, y) && !p.holes.some(h => inRing(h, x, y))))
152
+ return c.code;
153
+ }
154
+ return nearestWithin(all, x, y, COASTAL_REACH_KM);
155
+ }
156
+ /** Ceuta and Melilla, which the ministry publishes, are covered to their edges. */
157
+ const EXCLAVE_KM = 8;
158
+ /** A listed Moroccan town the outline's border runs through (Ahfir, Lagouira). */
159
+ const LISTED_TOWN_KM = 5;
160
+ /**
161
+ * The authority whose table a point's community prays by: Sweden's inside
162
+ * Sweden, Morocco's in Morocco (with Western Sahara, and Ceuta and Melilla,
163
+ * which the ministry lists — when `mihrab-methods/morocco` is loaded, so
164
+ * its cities can be consulted), Algeria's, Indonesia's, and Diyanet's in
165
+ * Türkiye and Northern Cyprus. Null elsewhere: Diyanet publishes tables
166
+ * for places in 197 other countries, but it is not those countries' own
167
+ * authority, so an app offers it there as a choice, not as the default.
168
+ */
169
+ export function defaultAuthorityFor(latitude, longitude) {
170
+ const code = countryAt(latitude, longitude);
171
+ switch (code) {
172
+ case 'SE':
173
+ return 'sweden';
174
+ case 'MA':
175
+ return 'morocco';
176
+ case 'DZ':
177
+ return 'algeria';
178
+ case 'ID':
179
+ return 'indonesia';
180
+ case 'TR':
181
+ return 'diyanet';
182
+ case 'ES':
183
+ case 'MR': {
184
+ if (!isLoaded('morocco'))
185
+ return null;
186
+ const near = nearestPlace('morocco', latitude, longitude);
187
+ if (!near)
188
+ return null;
189
+ const within = near.distanceKm <= (code === 'ES' ? EXCLAVE_KM : LISTED_TOWN_KM);
190
+ // Spain's cities the ministry lists are its two on the African coast.
191
+ return within && (code !== 'ES' || latitude < 35.95) ? 'morocco' : null;
192
+ }
193
+ default:
194
+ return null;
195
+ }
196
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Algeria — the Ministry of Religious Affairs and Wakfs's method, as its
3
+ * timetable is computed (issue #70).
4
+ *
5
+ * Read off the Ministry's own 1448 AH table (68 cities, 248 days each):
6
+ *
7
+ * • the Sun from NOAA's formulas (the solar-calculator series for the
8
+ * equation of time; its declination). They fit the table far better
9
+ * than a precise ephemeris (JPL DE421) or Meeus's chapter-25 Sun, so
10
+ * this is what the Ministry's program uses, not an approximation of it;
11
+ * • Dhuhr at the Sun's transit, the equation of time taken there;
12
+ * • every other time the transit plus or minus the hour angle, with the
13
+ * declination taken at that prayer's own moment (iterated) and the
14
+ * equation of time kept at noon's value;
15
+ * • Fajr 18°, Isha 17°, sunrise and sunset at −0.833°;
16
+ * • Asr from the noon shadow tan(φ − δ) WITH its sign, so where the Sun
17
+ * culminates north of the zenith (In Guezzam, Bordj Badji Mokhtar,
18
+ * Tamanrasset around June) Asr comes earlier, up to thirteen minutes;
19
+ * • Maghrib three minutes after sunset;
20
+ * • every time rounded UP to the minute.
21
+ *
22
+ * At each city's own point this gives the Ministry's minute for 99.4% of
23
+ * the published times; every other one is a single minute, where the
24
+ * exact time falls within about a second of a minute's edge (see
25
+ * `tools/verify-methods/README.md`).
26
+ */
27
+ export type AlgeriaInstants = {
28
+ fajr: Date;
29
+ sunrise: Date;
30
+ dhuhr: Date;
31
+ asr: Date;
32
+ maghrib: Date;
33
+ isha: Date;
34
+ };
35
+ /** NOAA's Sun at `d` days from J2000.0 (UT): declination (rad), equation of time (minutes). */
36
+ export declare function noaaSun(d: number): {
37
+ dec: number;
38
+ eot: number;
39
+ };
40
+ /**
41
+ * The day's exact times, minutes past 00:00 UT of the civil date, before
42
+ * rounding. NaN where the Sun never reaches the angle (not in Algeria).
43
+ */
44
+ export declare function algeriaRawMinutes(latitude: number, longitude: number, year: number, month: number, day: number, asrShadow?: number): {
45
+ fajr: number;
46
+ sunrise: number;
47
+ dhuhr: number;
48
+ asr: number;
49
+ sunset: number;
50
+ isha: number;
51
+ };
52
+ /**
53
+ * The Ministry's times for a point and civil date (month 0-based), as
54
+ * instants on the minute. Null when a time does not form at that point.
55
+ */
56
+ export declare function algeriaTimes(latitude: number, longitude: number, year: number, month: number, day: number, asrShadow?: number): AlgeriaInstants | null;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Algeria — the Ministry of Religious Affairs and Wakfs's method, as its
3
+ * timetable is computed (issue #70).
4
+ *
5
+ * Read off the Ministry's own 1448 AH table (68 cities, 248 days each):
6
+ *
7
+ * • the Sun from NOAA's formulas (the solar-calculator series for the
8
+ * equation of time; its declination). They fit the table far better
9
+ * than a precise ephemeris (JPL DE421) or Meeus's chapter-25 Sun, so
10
+ * this is what the Ministry's program uses, not an approximation of it;
11
+ * • Dhuhr at the Sun's transit, the equation of time taken there;
12
+ * • every other time the transit plus or minus the hour angle, with the
13
+ * declination taken at that prayer's own moment (iterated) and the
14
+ * equation of time kept at noon's value;
15
+ * • Fajr 18°, Isha 17°, sunrise and sunset at −0.833°;
16
+ * • Asr from the noon shadow tan(φ − δ) WITH its sign, so where the Sun
17
+ * culminates north of the zenith (In Guezzam, Bordj Badji Mokhtar,
18
+ * Tamanrasset around June) Asr comes earlier, up to thirteen minutes;
19
+ * • Maghrib three minutes after sunset;
20
+ * • every time rounded UP to the minute.
21
+ *
22
+ * At each city's own point this gives the Ministry's minute for 99.4% of
23
+ * the published times; every other one is a single minute, where the
24
+ * exact time falls within about a second of a minute's edge (see
25
+ * `tools/verify-methods/README.md`).
26
+ */
27
+ const RAD = Math.PI / 180;
28
+ const DAY_MS = 86_400_000;
29
+ /** NOAA's Sun at `d` days from J2000.0 (UT): declination (rad), equation of time (minutes). */
30
+ export function noaaSun(d) {
31
+ const T = d / 36525;
32
+ const L0 = (((280.46646 + T * (36000.76983 + 0.0003032 * T)) % 360) + 360) % 360;
33
+ const M = 357.52911 + T * (35999.05029 - 0.0001537 * T);
34
+ const ecc = 0.016708634 - T * (0.000042037 + 0.0000001267 * T);
35
+ const Mr = M * RAD;
36
+ const C = (1.914602 - T * (0.004817 + 0.000014 * T)) * Math.sin(Mr) +
37
+ (0.019993 - 0.000101 * T) * Math.sin(2 * Mr) +
38
+ 0.000289 * Math.sin(3 * Mr);
39
+ const om = (125.04 - 1934.136 * T) * RAD;
40
+ const lambda = L0 + C - 0.00569 - 0.00478 * Math.sin(om);
41
+ const eps0 = 23 + (26 + (21.448 - T * (46.815 + T * (0.00059 - T * 0.001813))) / 60) / 60;
42
+ const eps = eps0 + 0.00256 * Math.cos(om);
43
+ const dec = Math.asin(Math.sin(eps * RAD) * Math.sin(lambda * RAD));
44
+ const y = Math.tan((eps0 * RAD) / 2) ** 2;
45
+ const L0r = L0 * RAD;
46
+ const eot = (4 / RAD) *
47
+ (y * Math.sin(2 * L0r) -
48
+ 2 * ecc * Math.sin(Mr) +
49
+ 4 * ecc * y * Math.sin(Mr) * Math.cos(2 * L0r) -
50
+ 0.5 * y * y * Math.sin(4 * L0r) -
51
+ 1.25 * ecc * ecc * Math.sin(2 * Mr));
52
+ return { dec, eot };
53
+ }
54
+ const ITERATIONS = 3;
55
+ /**
56
+ * The day's exact times, minutes past 00:00 UT of the civil date, before
57
+ * rounding. NaN where the Sun never reaches the angle (not in Algeria).
58
+ */
59
+ export function algeriaRawMinutes(latitude, longitude, year, month, day, asrShadow = 1) {
60
+ const d0 = (Date.UTC(year, month, day) - Date.UTC(2000, 0, 1)) / DAY_MS - 0.5;
61
+ const at = (t) => noaaSun(d0 + t / 1440);
62
+ let noon = 720 - 4 * longitude;
63
+ for (let i = 0; i < ITERATIONS; i++)
64
+ noon = 720 - 4 * longitude - at(noon).eot;
65
+ const transit = 720 - 4 * longitude - at(noon).eot;
66
+ const sp = Math.sin(latitude * RAD);
67
+ const cp = Math.cos(latitude * RAD);
68
+ const event = (altitudeOf, sign, start) => {
69
+ let t = start;
70
+ for (let i = 0; i < ITERATIONS; i++) {
71
+ const { dec } = at(t);
72
+ const c = (Math.sin(altitudeOf(dec) * RAD) - sp * Math.sin(dec)) / (cp * Math.cos(dec));
73
+ if (!(Math.abs(c) <= 1))
74
+ return NaN;
75
+ t = transit + (sign * 4 * Math.acos(c)) / RAD;
76
+ }
77
+ return t;
78
+ };
79
+ const fixed = (a) => () => a;
80
+ const asrAltitude = (dec) => Math.atan(1 / (asrShadow + Math.tan((latitude - dec / RAD) * RAD))) / RAD;
81
+ return {
82
+ fajr: event(fixed(-18), -1, noon - 420),
83
+ sunrise: event(fixed(-0.833), -1, noon - 360),
84
+ dhuhr: noon,
85
+ asr: event(asrAltitude, 1, noon + 200),
86
+ sunset: event(fixed(-0.833), 1, noon + 360),
87
+ isha: event(fixed(-17), 1, noon + 420),
88
+ };
89
+ }
90
+ const MAGHRIB_AFTER_SUNSET_MIN = 3;
91
+ /** Rounded up to the minute, as the Ministry prints. */
92
+ function up(m) {
93
+ return Math.ceil(m - 1e-9);
94
+ }
95
+ /**
96
+ * The Ministry's times for a point and civil date (month 0-based), as
97
+ * instants on the minute. Null when a time does not form at that point.
98
+ */
99
+ export function algeriaTimes(latitude, longitude, year, month, day, asrShadow = 1) {
100
+ const r = algeriaRawMinutes(latitude, longitude, year, month, day, asrShadow);
101
+ const all = [r.fajr, r.sunrise, r.dhuhr, r.asr, r.sunset, r.isha];
102
+ if (!all.every(Number.isFinite))
103
+ return null;
104
+ const start = Date.UTC(year, month, day);
105
+ const at = (m) => new Date(start + up(m) * 60_000);
106
+ return {
107
+ fajr: at(r.fajr),
108
+ sunrise: at(r.sunrise),
109
+ dhuhr: at(r.dhuhr),
110
+ asr: at(r.asr),
111
+ maghrib: at(r.sunset + MAGHRIB_AFTER_SUNSET_MIN),
112
+ isha: at(r.isha),
113
+ };
114
+ }
@@ -0,0 +1,31 @@
1
+ export type KemenagInstants = {
2
+ fajr: Date;
3
+ sunrise: Date;
4
+ dhuhr: Date;
5
+ asr: Date;
6
+ maghrib: Date;
7
+ isha: Date;
8
+ };
9
+ export type KemenagPlaceOptions = {
10
+ /** The ministry's highland class: sunrise and Maghrib at −2° rather than −1°. */
11
+ highland?: boolean;
12
+ /** The highland degree on Fajr and Isha as well (six regencies of Papua). */
13
+ twilightDip?: boolean;
14
+ asrShadow?: number;
15
+ /**
16
+ * Where the ministry computes the regency's Asr, Maghrib and Isha, when not
17
+ * at its point (Karawang's afternoon is computed about 2 km north-east).
18
+ */
19
+ afternoon?: readonly [number, number];
20
+ };
21
+ /** Exact times with the margins, minutes past 00:00 UT of the civil date, before rounding. */
22
+ export declare function kemenagRawMinutes(latitude: number, longitude: number, year: number, month: number, day: number, opts?: KemenagPlaceOptions): {
23
+ fajr: number;
24
+ sunrise: number;
25
+ dhuhr: number;
26
+ asr: number;
27
+ maghrib: number;
28
+ isha: number;
29
+ };
30
+ /** The ministry's times for a point and civil date (month 0-based), on the minute; null where one does not form. */
31
+ export declare function kemenagTimes(latitude: number, longitude: number, year: number, month: number, day: number, opts?: KemenagPlaceOptions): KemenagInstants | null;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Indonesia — the Ministry of Religious Affairs' (Kemenag) method, as its
3
+ * timetable is computed.
4
+ *
5
+ * Read off its table for all 517 regencies and cities (October–December
6
+ * 2026):
7
+ *
8
+ * • the precise apparent Sun (`preciseApparentSun`, as JPL's to a tenth
9
+ * of a second), taken at each prayer's own moment, iterated — Meeus's
10
+ * shorter series drifts by a second and left a minute in two hundred
11
+ * off;
12
+ * • Fajr 20°, Isha 18°; sunrise and Maghrib at −1°, and at −2° in the
13
+ * regencies the ministry classes as highland — in six highland
14
+ * regencies of Papua the degree is taken off Fajr and Isha too;
15
+ * • Asr when the shadow is its length plus the noon shadow, the noon
16
+ * shadow from the Sun's declination at 00:00 UT of the day (as an
17
+ * almanac's daily entry gives it), the hour angle from the Sun at Asr;
18
+ * • every time rounded up, after a margin of two minutes (three for
19
+ * Dhuhr, minus three for sunrise).
20
+ *
21
+ * At each regency's own point (fitted to the table; Karawang's afternoon
22
+ * at a second one) this gives the ministry's minute for 99.969 % of its
23
+ * times, and never a minute further; the rest are within about a second
24
+ * of a minute's edge, with no pattern a model could take
25
+ * (`data/corrections/indonesia.json` has them).
26
+ */
27
+ import { preciseApparentSun } from '../sun/preciseSun.js';
28
+ const RAD = Math.PI / 180;
29
+ const DAY_MS = 86_400_000;
30
+ const ITERATIONS = 3;
31
+ const MARGIN = { fajr: 2, sunrise: -3, dhuhr: 3, asr: 2, maghrib: 2, isha: 2 };
32
+ const ASR_ITERATIONS = 4;
33
+ /** Exact times with the margins, minutes past 00:00 UT of the civil date, before rounding. */
34
+ export function kemenagRawMinutes(latitude, longitude, year, month, day, opts = {}) {
35
+ const d0 = (Date.UTC(year, month, day) - Date.UTC(2000, 0, 1)) / DAY_MS - 0.5;
36
+ const at = (t) => preciseApparentSun(d0 + t / 1440);
37
+ let noon = 720 - 4 * longitude;
38
+ for (let i = 0; i < ITERATIONS; i++)
39
+ noon = 720 - 4 * longitude - at(noon).eot;
40
+ const sp = Math.sin(latitude * RAD);
41
+ const cp = Math.cos(latitude * RAD);
42
+ const hourAngle = (alt, dec) => {
43
+ const c = (Math.sin(alt * RAD) - sp * Math.sin(dec)) / (cp * Math.cos(dec));
44
+ return Math.abs(c) <= 1 ? (4 * Math.acos(c)) / RAD : NaN;
45
+ };
46
+ const event = (alt, sign, start) => {
47
+ let t = start;
48
+ for (let i = 0; i < ITERATIONS; i++) {
49
+ const { dec, eot } = at(t);
50
+ t = 720 - 4 * longitude - eot + sign * hourAngle(alt, dec);
51
+ if (!Number.isFinite(t))
52
+ return NaN;
53
+ }
54
+ return t;
55
+ };
56
+ const twilight = opts.twilightDip ? 1 : 0;
57
+ const horizon = opts.highland ? -2 : -1;
58
+ // The noon shadow from the declination at 00:00 UT; the hour angle from the Sun at Asr, iterated.
59
+ const shadowDec = at(0).dec;
60
+ const asrAlt = Math.atan(1 / ((opts.asrShadow ?? 1) + Math.tan(Math.abs(latitude * RAD - shadowDec)))) / RAD;
61
+ let asr = noon + 200;
62
+ for (let i = 0; i < ASR_ITERATIONS; i++) {
63
+ const { dec, eot } = at(asr);
64
+ asr = 720 - 4 * longitude - eot + hourAngle(asrAlt, dec);
65
+ }
66
+ return {
67
+ fajr: event(-20 - twilight, -1, noon - 420) + MARGIN.fajr,
68
+ sunrise: event(horizon, -1, noon - 360) + MARGIN.sunrise,
69
+ dhuhr: noon + MARGIN.dhuhr,
70
+ asr: asr + MARGIN.asr,
71
+ maghrib: event(horizon, 1, noon + 360) + MARGIN.maghrib,
72
+ isha: event(-18 - twilight, 1, noon + 420) + MARGIN.isha,
73
+ };
74
+ }
75
+ /** The ministry's times for a point and civil date (month 0-based), on the minute; null where one does not form. */
76
+ export function kemenagTimes(latitude, longitude, year, month, day, opts = {}) {
77
+ const r = kemenagRawMinutes(latitude, longitude, year, month, day, opts);
78
+ if (opts.afternoon) {
79
+ const pm = kemenagRawMinutes(opts.afternoon[0], opts.afternoon[1], year, month, day, opts);
80
+ r.asr = pm.asr;
81
+ r.maghrib = pm.maghrib;
82
+ r.isha = pm.isha;
83
+ }
84
+ const all = [r.fajr, r.sunrise, r.dhuhr, r.asr, r.maghrib, r.isha];
85
+ if (!all.every(Number.isFinite))
86
+ return null;
87
+ const start = Date.UTC(year, month, day);
88
+ const at = (m) => new Date(start + Math.ceil(m - 1e-9) * 60_000);
89
+ return { fajr: at(r.fajr), sunrise: at(r.sunrise), dhuhr: at(r.dhuhr), asr: at(r.asr), maghrib: at(r.maghrib), isha: at(r.isha) };
90
+ }