mihrab-methods 1.0.1 → 1.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 (47) hide show
  1. package/README.md +104 -287
  2. package/certification.json +31 -20
  3. package/data/corrections/indonesia.json +721 -28
  4. package/data/corrections/morocco.json +201 -914
  5. package/dist/cjs/authorities/morocco.js +7 -6
  6. package/dist/cjs/core/compute.js +1 -1
  7. package/dist/cjs/core/types.d.ts +4 -0
  8. package/dist/cjs/data/generated/algeriaCertification.js +1 -1
  9. package/dist/cjs/data/generated/diyanetCertification.js +1 -1
  10. package/dist/cjs/data/generated/diyanetWorldPoints.js +1 -1
  11. package/dist/cjs/data/generated/indonesiaCertification.js +1 -1
  12. package/dist/cjs/data/generated/indonesiaCorrections.js +1 -1
  13. package/dist/cjs/data/generated/moroccoCertification.js +1 -1
  14. package/dist/cjs/data/generated/moroccoCorrections.js +1 -1
  15. package/dist/cjs/data/generated/moroccoMethodPoints.js +1 -1
  16. package/dist/cjs/data/generated/swedenCertification.js +1 -1
  17. package/dist/cjs/methods/morocco.d.ts +43 -20
  18. package/dist/cjs/methods/morocco.js +59 -25
  19. package/dist/cjs/methods/revisions.d.ts +1 -1
  20. package/dist/cjs/methods/revisions.js +1 -1
  21. package/dist/cjs/server.d.ts +12 -0
  22. package/dist/cjs/server.js +132 -0
  23. package/dist/esm/authorities/morocco.js +7 -6
  24. package/dist/esm/core/compute.js +1 -1
  25. package/dist/esm/core/types.d.ts +4 -0
  26. package/dist/esm/data/generated/algeriaCertification.js +1 -1
  27. package/dist/esm/data/generated/diyanetCertification.js +1 -1
  28. package/dist/esm/data/generated/diyanetWorldPoints.js +1 -1
  29. package/dist/esm/data/generated/indonesiaCertification.js +1 -1
  30. package/dist/esm/data/generated/indonesiaCorrections.js +1 -1
  31. package/dist/esm/data/generated/moroccoCertification.js +1 -1
  32. package/dist/esm/data/generated/moroccoCorrections.js +1 -1
  33. package/dist/esm/data/generated/moroccoMethodPoints.js +1 -1
  34. package/dist/esm/data/generated/swedenCertification.js +1 -1
  35. package/dist/esm/methods/morocco.d.ts +43 -20
  36. package/dist/esm/methods/morocco.js +54 -24
  37. package/dist/esm/methods/revisions.d.ts +1 -1
  38. package/dist/esm/methods/revisions.js +1 -1
  39. package/dist/esm/server.d.ts +12 -0
  40. package/dist/esm/server.js +126 -0
  41. package/docs/methods.md +24 -8
  42. package/package.json +5 -1
  43. package/schemas/certification.schema.json +119 -24
  44. package/dist/cjs/methods/scratch-congress.d.ts +0 -87
  45. package/dist/cjs/methods/scratch-congress.js +0 -539
  46. package/dist/esm/methods/scratch-congress.d.ts +0 -87
  47. package/dist/esm/methods/scratch-congress.js +0 -534
package/docs/methods.md CHANGED
@@ -110,7 +110,11 @@ statement of it that gives the tables.
110
110
  ## Morocco
111
111
 
112
112
  `src/methods/morocco.ts`. The Ministry of Habous and Islamic Affairs, read
113
- off its tables for 164 cities.
113
+ off its tables for 164 cities: 96 days of 2026 for all of them, and — through
114
+ the Internet Archive's copies of its pages — 2014 to 2025 for Rabat, Figuig,
115
+ Tangier, Casablanca, Laayoune and a dozen more, every month of the year. The
116
+ ministry's program changed between 2019 and 2023 (until then Asr was the
117
+ noon shadow on the true sun); this is the program it has used since.
114
118
 
115
119
  - The sun is **Meeus's apparent sun** with the full nutation (the mean
116
120
  elements above; apparent longitude `L0 + C − 0.00569 + Δψ`, with
@@ -118,14 +122,26 @@ off its tables for 164 cities.
118
122
  and his chapter-28 equation of time
119
123
  `E = L0 − 0.0057183 − α + Δψ cos ε`, taken at **each prayer's own
120
124
  moment** (iterated), declination and equation of time alike.
121
- - Fajr −19°, Isha −17°, Asr one shadow length (Shafiʿi).
125
+ - Fajr −19°, Isha −17°, true altitudes.
122
126
  - Dhuhr five minutes after the transit.
123
- - Sunrise 2.85 minutes before, and Maghrib 3.7 minutes after, the sun's
124
- upper limb on the horizon: altitude `−(34′ + s) − dip`, with s the sun's
125
- semi-diameter for its distance that day and dip the city's own horizon
126
- dip — eastward at sunrise (`Place.dipDeg`), westward at Maghrib
127
- (`Place.dipMaghribDeg`), each fitted from the tables with the city's
128
- point; where not fitted, `0.02°·√height(m)`, and 0.86 of it at Maghrib.
127
+ - Asr on the **apparent** sun, by the classical rule: with δ the noon
128
+ declination, the noon altitude `h = 90° − |φ − δ|` is raised by
129
+ refraction, `h' = h + R(h)`, `R(h) = 1.02′ / tan(h + 10.3/(h + 5.11))`
130
+ (Sæmundsson, Meeus 16.4, h in degrees); the gnomon's shadow is `cot h'`,
131
+ and Asr is when the apparent sun's shadow is one length more:
132
+ apparent altitude `a' = arctan(1 / (1 + cot h'))`, and the true altitude
133
+ the hour angle is solved for, `a = a' − R'(a')`,
134
+ `R'(a') = 1′ / tan(a' + 7.31/(a' + 4.4))` (Bennett, Meeus 16.3), with the
135
+ declination at the event. Hanafi takes two lengths.
136
+ - Sunrise one minute before, and Maghrib 1.8 minutes after, the sun on the
137
+ altitude `−(34′ + s) − dip`, with s the sun's semi-diameter for its
138
+ distance that day and dip the city's own horizon allowance — eastward at
139
+ sunrise (`Place.dipDeg`), westward at Maghrib (`Place.dipMaghribDeg`),
140
+ each fitted from the tables with the city's point. It is an angle: the
141
+ minutes it is worth grow towards the solstices, as the ministry's do.
142
+ It follows the city's height (92 % correlation), and a city not fitted
143
+ gets `0.32° + 0.025°·√height(m)` east and `0.37° + 0.021°·√height(m)`
144
+ west.
129
145
  - Fajr rounded **down** to the minute, every other time to the nearest.
130
146
  - The ministry's clock is GMT+1 until 17 September 2026 and GMT from then
131
147
  on (`Place.clock`); the zone databases still move Morocco's clock, so the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mihrab-methods",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "The prayer-time authorities' own calculation methods, each reproducing its published timetable to the minute: Sweden (Diyanet, as Islamiska Förbundet prints it), Diyanet worldwide, Morocco (Habous), Algeria (Ministry of Religious Affairs), Indonesia (Kemenag).",
5
5
  "license": "MPL-2.0",
6
6
  "author": "Hassan El Ghamri",
@@ -169,6 +169,10 @@
169
169
  "precertify": "npm run embed",
170
170
  "certify": "tsx tools/certify.ts",
171
171
  "vectors": "npm run embed && tsx tools/vectors.ts",
172
+ "prefeed-check": "npm run embed",
173
+ "feed-check": "tsx tools/feed-check.ts",
174
+ "readme": "node scripts/readme.mjs",
175
+ "preflight": "npm run typecheck && npm test && node scripts/readme.mjs --check",
172
176
  "serve": "npm run embed && tsx tools/serve.ts"
173
177
  },
174
178
  "devDependencies": {
@@ -4,54 +4,149 @@
4
4
  "title": "mihrab-methods certification",
5
5
  "description": "What may be used: for each authority, whether its method reproduces every time of the authority's tables on the printed minute, over which dates, at which method revision, and which correction list that holds with. Written by `npm run certify`; read by apps to keep current (fetchLatestCorrections).",
6
6
  "type": "object",
7
- "propertyNames": { "enum": ["sweden", "diyanet", "morocco", "algeria", "indonesia"] },
8
- "additionalProperties": { "$ref": "#/$defs/entry" },
7
+ "propertyNames": {
8
+ "enum": [
9
+ "sweden",
10
+ "diyanet",
11
+ "morocco",
12
+ "algeria",
13
+ "indonesia"
14
+ ]
15
+ },
16
+ "additionalProperties": {
17
+ "$ref": "#/$defs/entry"
18
+ },
9
19
  "$defs": {
10
- "date": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" },
20
+ "date": {
21
+ "type": "string",
22
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
23
+ },
11
24
  "entry": {
12
25
  "type": "object",
13
- "required": ["certified", "checkedAt", "checks"],
26
+ "required": [
27
+ "certified",
28
+ "checkedAt",
29
+ "checks"
30
+ ],
14
31
  "additionalProperties": false,
15
32
  "properties": {
16
- "certified": { "type": "boolean", "description": "True only when every check below has every time on the printed minute. Not trusted alone: apps re-derive it from the checks." },
17
- "checkedAt": { "$ref": "#/$defs/date" },
18
- "checks": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/check" } },
33
+ "certified": {
34
+ "type": "boolean",
35
+ "description": "True only when every check below has every time on the printed minute. Not trusted alone: apps re-derive it from the checks."
36
+ },
37
+ "checkedAt": {
38
+ "$ref": "#/$defs/date"
39
+ },
40
+ "places": {
41
+ "type": "integer",
42
+ "minimum": 0,
43
+ "description": "How many places the library offers for the authority (the checks say how many were compared)."
44
+ },
45
+ "checks": {
46
+ "type": "array",
47
+ "minItems": 1,
48
+ "items": {
49
+ "$ref": "#/$defs/check"
50
+ }
51
+ },
19
52
  "corrections": {
20
53
  "type": "object",
21
54
  "description": "The correction list this certification is for: its identity, and the SHA-256 of data/corrections/<authority>.json as published.",
22
- "required": ["from", "to", "entries"],
55
+ "required": [
56
+ "from",
57
+ "to",
58
+ "entries"
59
+ ],
23
60
  "additionalProperties": false,
24
61
  "properties": {
25
- "from": { "$ref": "#/$defs/date" },
26
- "to": { "$ref": "#/$defs/date" },
27
- "entries": { "type": "integer", "minimum": 0 },
28
- "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" }
62
+ "from": {
63
+ "$ref": "#/$defs/date"
64
+ },
65
+ "to": {
66
+ "$ref": "#/$defs/date"
67
+ },
68
+ "entries": {
69
+ "type": "integer",
70
+ "minimum": 0
71
+ },
72
+ "sha256": {
73
+ "type": "string",
74
+ "pattern": "^[0-9a-f]{64}$"
75
+ }
29
76
  }
30
77
  },
31
- "revision": { "type": "integer", "minimum": 1, "description": "The method's revision the list is for. An app computing another revision must not apply the list." }
78
+ "revision": {
79
+ "type": "integer",
80
+ "minimum": 1,
81
+ "description": "The method's revision the list is for. An app computing another revision must not apply the list."
82
+ }
32
83
  }
33
84
  },
34
85
  "check": {
35
86
  "type": "object",
36
- "required": ["tables", "places", "times", "off", "from", "to"],
87
+ "required": [
88
+ "tables",
89
+ "places",
90
+ "times",
91
+ "off",
92
+ "from",
93
+ "to"
94
+ ],
37
95
  "additionalProperties": false,
38
96
  "properties": {
39
- "tables": { "type": "string", "description": "Whose tables were checked." },
40
- "places": { "type": "integer", "minimum": 0 },
41
- "times": { "type": "integer", "minimum": 0 },
42
- "off": { "type": "integer", "minimum": 0, "description": "Times not on the printed minute. Certified only at 0." },
43
- "from": { "$ref": "#/$defs/date" },
44
- "to": { "$ref": "#/$defs/date" },
97
+ "tables": {
98
+ "type": "string",
99
+ "description": "Whose tables were checked."
100
+ },
101
+ "places": {
102
+ "type": "integer",
103
+ "minimum": 0
104
+ },
105
+ "times": {
106
+ "type": "integer",
107
+ "minimum": 0
108
+ },
109
+ "off": {
110
+ "type": "integer",
111
+ "minimum": 0,
112
+ "description": "Times not on the printed minute. Certified only at 0."
113
+ },
114
+ "from": {
115
+ "$ref": "#/$defs/date"
116
+ },
117
+ "to": {
118
+ "$ref": "#/$defs/date"
119
+ },
45
120
  "setAside": {
46
121
  "type": "object",
47
122
  "description": "Rows set aside as the source's fault, not the method's, so each can be judged.",
48
- "required": ["misplaced", "sourceFaults", "copiedRows"],
123
+ "required": [
124
+ "misplaced",
125
+ "sourceFaults",
126
+ "copiedRows"
127
+ ],
49
128
  "additionalProperties": false,
50
129
  "properties": {
51
- "misplaced": { "type": "array", "items": { "type": "string" } },
52
- "sourceFaults": { "type": "integer", "minimum": 0 },
53
- "copiedRows": { "type": "integer", "minimum": 0 }
130
+ "misplaced": {
131
+ "type": "array",
132
+ "items": {
133
+ "type": "string"
134
+ }
135
+ },
136
+ "sourceFaults": {
137
+ "type": "integer",
138
+ "minimum": 0
139
+ },
140
+ "copiedRows": {
141
+ "type": "integer",
142
+ "minimum": 0
143
+ }
54
144
  }
145
+ },
146
+ "offWithoutCorrections": {
147
+ "type": "integer",
148
+ "minimum": 0,
149
+ "description": "Of the same times, how many the method alone, without its correction list, leaves off the printed minute."
55
150
  }
56
151
  }
57
152
  }
@@ -1,87 +0,0 @@
1
- /**
2
- * The International Prayer Times Congress method (Istanbul, 2021 — the
3
- * Diyanet and the European Council for Fatwa and Research) as Diyanet's
4
- * tables realise it. Islamiska Förbundet's Swedish tables are those
5
- * tables, row for row, so this is Sweden's method (id 24).
6
- *
7
- * The published rules (awqatsalah.com, "Tespit Kriterleri"):
8
- * - Dhuhr five minutes after transit; Asr one shadow (Dhuhr when the
9
- * shadow never forms), four minutes late; sunrise seven early,
10
- * Maghrib seven late ("temkin").
11
- * - Neither the day nor the night is shorter than five hours.
12
- * - True Fajr at 18°, true Isha at 16°. Where the 18° dawn no longer
13
- * forms, the share of the night the sharia night's third took on the
14
- * last day it did is carried: Isha that share of the night after
15
- * Maghrib, Fajr the same share scaled by 18/16 before sunrise.
16
- * - The move from true times to the carried ones is gradual, starting
17
- * twenty minutes before (Isha) or after (Fajr) the takdir.
18
- *
19
- * What the tables turn out to do with them, read off Diyanet's own tables
20
- * for all 160 Swedish places, 2024–2027 (99.98 % of times on the printed
21
- * minute, the rest a fraction of a second from the rounding point):
22
- * - The sun is taken once a day, at 0h UT less 45 s: Meeus's mean
23
- * elements and equation of the centre, the TRUE (geometric) longitude,
24
- * the apparent obliquity (mean plus nutation), the equation of time as
25
- * the mean longitude less the right ascension, 0.106 s later; and
26
- * two small waves by the mean longitude the formula leaves out: a few
27
- * hundredths of a second on the transit, a tenth of an arc-second on
28
- * the declination.
29
- * - Coordinates are kept to three decimals of a degree.
30
- * - Asr that never forms is printed at Dhuhr's time.
31
- * - The night a share is taken of is the day's own: 24 h less the
32
- * printed day, sunrise to Maghrib.
33
- * - The five-hour floors hold each end separately, 150 minutes from the
34
- * printed Dhuhr or from the midnight after it. Where midsummer's
35
- * night is floored at both ends (to within a minute), that night
36
- * anchors the season, and the floored times never step back: before
37
- * midsummer no sunrise earlier than midsummer's and a floored Maghrib
38
- * no earlier than the day before; after it no sunrise earlier nor
39
- * Maghrib later than on any day since midsummer — and Fajr and Isha
40
- * carried the same way.
41
- * - The gradual transition is a straight line across the days next to
42
- * the gap on which the true time lies within twenty minutes of the
43
- * takdir at the gap's edge: twenty minutes away at the far end, the
44
- * takdir at the edge.
45
- *
46
- * Beyond Sweden the same code gives Diyanet's tables worldwide, read off
47
- * them for places on six continents:
48
- * - Where the dawn forms all summer but midsummer's true Isha (at 16°)
49
- * falls later than the share carried from that night, midsummer is the
50
- * takdir's day — a gap of one day, with its ramps (from about 44.4°
51
- * north: Austria, central France, northern Bosnia).
52
- * - Isha is printed at 16° in some countries and 17° in others; the
53
- * high-latitude rules are worked at 16° either way (`ishaDeg`).
54
- *
55
- * Times are minutes past 0h UT of the date, a frame the clock changes
56
- * cannot bend; `congressTimes` turns them into instants.
57
- */
58
- /**
59
- * Isha's depression: the Congress's 16° (Diyanet's in much of Europe,
60
- * Russia, Central Asia, China and North America), or Diyanet's own 17°
61
- * (elsewhere). The high-latitude rules are the Congress's at 16° either way;
62
- * the angle sets only the true Isha printed.
63
- */
64
- export declare const CONGRESS_ISHA_DEG = 16;
65
- export declare const DIYANET_ISHA_DEG = 17;
66
- export type CongressInstants = {
67
- fajr: Date;
68
- sunrise: Date;
69
- dhuhr: Date;
70
- asr: Date;
71
- maghrib: Date;
72
- isha: Date;
73
- };
74
- /**
75
- * The Congress method's times for a calendar date (year, month 0–11, day),
76
- * as instants, unrounded. `asrShadow` is 1 for the standard Asr, 2 for the
77
- * Hanafi one; the tables print the standard. `ishaDeg` is Isha's depression:
78
- * 16° (the Congress's, Diyanet's in Europe and North America) or 17°
79
- * (Diyanet's everywhere else).
80
- */
81
- export declare function congressTimes(latitude: number, longitude: number, year: number, month: number, day: number, asrShadow?: number, ishaDeg?: number): CongressInstants;
82
- /** For tests and the verification tool: the year's structure as the method sees it. */
83
- export declare function congressYearInfo(latitude: number, longitude: number, year: number): {
84
- gap: [string, string] | null;
85
- ratio: number | null;
86
- midsummerFloors: boolean;
87
- };