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.
- package/LICENSE +373 -0
- package/README.md +319 -2
- package/certification.json +120 -0
- package/data/corrections/algeria.json +784 -0
- package/data/corrections/diyanet.json +18444 -0
- package/data/corrections/indonesia.json +210 -0
- package/data/corrections/morocco.json +993 -0
- package/data/corrections/sweden.json +516 -0
- package/dist/cjs/algeria.d.ts +4 -0
- package/dist/cjs/algeria.js +22 -0
- package/dist/cjs/authorities/algeria.d.ts +3 -0
- package/dist/cjs/authorities/algeria.js +57 -0
- package/dist/cjs/authorities/diyanet.d.ts +9 -0
- package/dist/cjs/authorities/diyanet.js +90 -0
- package/dist/cjs/authorities/indonesia.d.ts +4 -0
- package/dist/cjs/authorities/indonesia.js +82 -0
- package/dist/cjs/authorities/morocco.d.ts +5 -0
- package/dist/cjs/authorities/morocco.js +65 -0
- package/dist/cjs/authorities/slug.d.ts +2 -0
- package/dist/cjs/authorities/slug.js +17 -0
- package/dist/cjs/authorities/sweden.d.ts +3 -0
- package/dist/cjs/authorities/sweden.js +58 -0
- package/dist/cjs/core/api.d.ts +61 -0
- package/dist/cjs/core/api.js +177 -0
- package/dist/cjs/core/civilDate.d.ts +17 -0
- package/dist/cjs/core/civilDate.js +41 -0
- package/dist/cjs/core/clock.d.ts +22 -0
- package/dist/cjs/core/clock.js +67 -0
- package/dist/cjs/core/compute.d.ts +10 -0
- package/dist/cjs/core/compute.js +59 -0
- package/dist/cjs/core/correctionList.d.ts +25 -0
- package/dist/cjs/core/correctionList.js +62 -0
- package/dist/cjs/core/fetchLatest.d.ts +61 -0
- package/dist/cjs/core/fetchLatest.js +192 -0
- package/dist/cjs/core/index.d.ts +14 -0
- package/dist/cjs/core/index.js +45 -0
- package/dist/cjs/core/registry.d.ts +28 -0
- package/dist/cjs/core/registry.js +34 -0
- package/dist/cjs/core/types.d.ts +193 -0
- package/dist/cjs/core/types.js +22 -0
- package/dist/cjs/core.d.ts +2 -0
- package/dist/cjs/core.js +18 -0
- package/dist/cjs/data/generated/algeriaCertification.d.ts +3 -0
- package/dist/cjs/data/generated/algeriaCertification.js +4 -0
- package/dist/cjs/data/generated/algeriaCities.d.ts +8 -0
- package/dist/cjs/data/generated/algeriaCities.js +5 -0
- package/dist/cjs/data/generated/algeriaCorrections.d.ts +3 -0
- package/dist/cjs/data/generated/algeriaCorrections.js +4 -0
- package/dist/cjs/data/generated/algeriaMethodPoints.d.ts +2 -0
- package/dist/cjs/data/generated/algeriaMethodPoints.js +5 -0
- package/dist/cjs/data/generated/countryOutlines.d.ts +5 -0
- package/dist/cjs/data/generated/countryOutlines.js +5 -0
- package/dist/cjs/data/generated/diyanetCertification.d.ts +3 -0
- package/dist/cjs/data/generated/diyanetCertification.js +4 -0
- package/dist/cjs/data/generated/diyanetCorrections.d.ts +3 -0
- package/dist/cjs/data/generated/diyanetCorrections.js +4 -0
- package/dist/cjs/data/generated/diyanetCountries.d.ts +5 -0
- package/dist/cjs/data/generated/diyanetCountries.js +5 -0
- package/dist/cjs/data/generated/diyanetTurkeyPoints.d.ts +7 -0
- package/dist/cjs/data/generated/diyanetTurkeyPoints.js +5 -0
- package/dist/cjs/data/generated/diyanetWorldPoints.d.ts +10 -0
- package/dist/cjs/data/generated/diyanetWorldPoints.js +5 -0
- package/dist/cjs/data/generated/indonesiaCertification.d.ts +3 -0
- package/dist/cjs/data/generated/indonesiaCertification.js +4 -0
- package/dist/cjs/data/generated/indonesiaCorrections.d.ts +3 -0
- package/dist/cjs/data/generated/indonesiaCorrections.js +4 -0
- package/dist/cjs/data/generated/kemenagMethodPoints.d.ts +2 -0
- package/dist/cjs/data/generated/kemenagMethodPoints.js +5 -0
- package/dist/cjs/data/generated/kemenagPlaces.d.ts +8 -0
- package/dist/cjs/data/generated/kemenagPlaces.js +5 -0
- package/dist/cjs/data/generated/moroccoCertification.d.ts +3 -0
- package/dist/cjs/data/generated/moroccoCertification.js +4 -0
- package/dist/cjs/data/generated/moroccoCities.d.ts +8 -0
- package/dist/cjs/data/generated/moroccoCities.js +5 -0
- package/dist/cjs/data/generated/moroccoCorrections.d.ts +3 -0
- package/dist/cjs/data/generated/moroccoCorrections.js +4 -0
- package/dist/cjs/data/generated/moroccoMethodPoints.d.ts +2 -0
- package/dist/cjs/data/generated/moroccoMethodPoints.js +5 -0
- package/dist/cjs/data/generated/swedenCertification.d.ts +3 -0
- package/dist/cjs/data/generated/swedenCertification.js +4 -0
- package/dist/cjs/data/generated/swedenCorrections.d.ts +3 -0
- package/dist/cjs/data/generated/swedenCorrections.js +4 -0
- package/dist/cjs/data/generated/swedenPlaces.d.ts +5 -0
- package/dist/cjs/data/generated/swedenPlaces.js +5 -0
- package/dist/cjs/diyanet.d.ts +4 -0
- package/dist/cjs/diyanet.js +22 -0
- package/dist/cjs/index.d.ts +19 -0
- package/dist/cjs/index.js +37 -0
- package/dist/cjs/indonesia.d.ts +4 -0
- package/dist/cjs/indonesia.js +22 -0
- package/dist/cjs/locate.d.ts +21 -0
- package/dist/cjs/locate.js +204 -0
- package/dist/cjs/methods/algeria.d.ts +56 -0
- package/dist/cjs/methods/algeria.js +119 -0
- package/dist/cjs/methods/indonesia.d.ts +31 -0
- package/dist/cjs/methods/indonesia.js +94 -0
- package/dist/cjs/methods/morocco.d.ts +61 -0
- package/dist/cjs/methods/morocco.js +113 -0
- package/dist/cjs/methods/revisions.d.ts +15 -0
- package/dist/cjs/methods/revisions.js +18 -0
- package/dist/cjs/methods/scratch-congress.d.ts +87 -0
- package/dist/cjs/methods/scratch-congress.js +539 -0
- package/dist/cjs/methods/sweden.d.ts +88 -0
- package/dist/cjs/methods/sweden.js +568 -0
- package/dist/cjs/morocco.d.ts +4 -0
- package/dist/cjs/morocco.js +22 -0
- package/dist/cjs/sun/preciseSun.d.ts +19 -0
- package/dist/cjs/sun/preciseSun.js +185 -0
- package/dist/cjs/sweden.d.ts +4 -0
- package/dist/cjs/sweden.js +22 -0
- package/dist/esm/algeria.d.ts +4 -0
- package/dist/esm/algeria.js +4 -0
- package/dist/esm/authorities/algeria.d.ts +3 -0
- package/dist/esm/authorities/algeria.js +51 -0
- package/dist/esm/authorities/diyanet.d.ts +9 -0
- package/dist/esm/authorities/diyanet.js +83 -0
- package/dist/esm/authorities/indonesia.d.ts +4 -0
- package/dist/esm/authorities/indonesia.js +75 -0
- package/dist/esm/authorities/morocco.d.ts +5 -0
- package/dist/esm/authorities/morocco.js +59 -0
- package/dist/esm/authorities/slug.d.ts +2 -0
- package/dist/esm/authorities/slug.js +14 -0
- package/dist/esm/authorities/sweden.d.ts +3 -0
- package/dist/esm/authorities/sweden.js +52 -0
- package/dist/esm/core/api.d.ts +61 -0
- package/dist/esm/core/api.js +163 -0
- package/dist/esm/core/civilDate.d.ts +17 -0
- package/dist/esm/core/civilDate.js +36 -0
- package/dist/esm/core/clock.d.ts +22 -0
- package/dist/esm/core/clock.js +60 -0
- package/dist/esm/core/compute.d.ts +10 -0
- package/dist/esm/core/compute.js +56 -0
- package/dist/esm/core/correctionList.d.ts +25 -0
- package/dist/esm/core/correctionList.js +56 -0
- package/dist/esm/core/fetchLatest.d.ts +61 -0
- package/dist/esm/core/fetchLatest.js +184 -0
- package/dist/esm/core/index.d.ts +14 -0
- package/dist/esm/core/index.js +14 -0
- package/dist/esm/core/registry.d.ts +28 -0
- package/dist/esm/core/registry.js +28 -0
- package/dist/esm/core/types.d.ts +193 -0
- package/dist/esm/core/types.js +18 -0
- package/dist/esm/core.d.ts +2 -0
- package/dist/esm/core.js +2 -0
- package/dist/esm/data/generated/algeriaCertification.d.ts +3 -0
- package/dist/esm/data/generated/algeriaCertification.js +2 -0
- package/dist/esm/data/generated/algeriaCities.d.ts +8 -0
- package/dist/esm/data/generated/algeriaCities.js +3 -0
- package/dist/esm/data/generated/algeriaCorrections.d.ts +3 -0
- package/dist/esm/data/generated/algeriaCorrections.js +2 -0
- package/dist/esm/data/generated/algeriaMethodPoints.d.ts +2 -0
- package/dist/esm/data/generated/algeriaMethodPoints.js +3 -0
- package/dist/esm/data/generated/countryOutlines.d.ts +5 -0
- package/dist/esm/data/generated/countryOutlines.js +3 -0
- package/dist/esm/data/generated/diyanetCertification.d.ts +3 -0
- package/dist/esm/data/generated/diyanetCertification.js +2 -0
- package/dist/esm/data/generated/diyanetCorrections.d.ts +3 -0
- package/dist/esm/data/generated/diyanetCorrections.js +2 -0
- package/dist/esm/data/generated/diyanetCountries.d.ts +5 -0
- package/dist/esm/data/generated/diyanetCountries.js +3 -0
- package/dist/esm/data/generated/diyanetTurkeyPoints.d.ts +7 -0
- package/dist/esm/data/generated/diyanetTurkeyPoints.js +3 -0
- package/dist/esm/data/generated/diyanetWorldPoints.d.ts +10 -0
- package/dist/esm/data/generated/diyanetWorldPoints.js +3 -0
- package/dist/esm/data/generated/indonesiaCertification.d.ts +3 -0
- package/dist/esm/data/generated/indonesiaCertification.js +2 -0
- package/dist/esm/data/generated/indonesiaCorrections.d.ts +3 -0
- package/dist/esm/data/generated/indonesiaCorrections.js +2 -0
- package/dist/esm/data/generated/kemenagMethodPoints.d.ts +2 -0
- package/dist/esm/data/generated/kemenagMethodPoints.js +3 -0
- package/dist/esm/data/generated/kemenagPlaces.d.ts +8 -0
- package/dist/esm/data/generated/kemenagPlaces.js +3 -0
- package/dist/esm/data/generated/moroccoCertification.d.ts +3 -0
- package/dist/esm/data/generated/moroccoCertification.js +2 -0
- package/dist/esm/data/generated/moroccoCities.d.ts +8 -0
- package/dist/esm/data/generated/moroccoCities.js +3 -0
- package/dist/esm/data/generated/moroccoCorrections.d.ts +3 -0
- package/dist/esm/data/generated/moroccoCorrections.js +2 -0
- package/dist/esm/data/generated/moroccoMethodPoints.d.ts +2 -0
- package/dist/esm/data/generated/moroccoMethodPoints.js +3 -0
- package/dist/esm/data/generated/swedenCertification.d.ts +3 -0
- package/dist/esm/data/generated/swedenCertification.js +2 -0
- package/dist/esm/data/generated/swedenCorrections.d.ts +3 -0
- package/dist/esm/data/generated/swedenCorrections.js +2 -0
- package/dist/esm/data/generated/swedenPlaces.d.ts +5 -0
- package/dist/esm/data/generated/swedenPlaces.js +3 -0
- package/dist/esm/diyanet.d.ts +4 -0
- package/dist/esm/diyanet.js +4 -0
- package/dist/esm/index.d.ts +19 -0
- package/dist/esm/index.js +19 -0
- package/dist/esm/indonesia.d.ts +4 -0
- package/dist/esm/indonesia.js +4 -0
- package/dist/esm/locate.d.ts +21 -0
- package/dist/esm/locate.js +196 -0
- package/dist/esm/methods/algeria.d.ts +56 -0
- package/dist/esm/methods/algeria.js +114 -0
- package/dist/esm/methods/indonesia.d.ts +31 -0
- package/dist/esm/methods/indonesia.js +90 -0
- package/dist/esm/methods/morocco.d.ts +61 -0
- package/dist/esm/methods/morocco.js +107 -0
- package/dist/esm/methods/revisions.d.ts +15 -0
- package/dist/esm/methods/revisions.js +15 -0
- package/dist/esm/methods/scratch-congress.d.ts +87 -0
- package/dist/esm/methods/scratch-congress.js +534 -0
- package/dist/esm/methods/sweden.d.ts +88 -0
- package/dist/esm/methods/sweden.js +563 -0
- package/dist/esm/morocco.d.ts +4 -0
- package/dist/esm/morocco.js +4 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/sun/preciseSun.d.ts +19 -0
- package/dist/esm/sun/preciseSun.js +181 -0
- package/dist/esm/sweden.d.ts +4 -0
- package/dist/esm/sweden.js +4 -0
- package/docs/methods.md +190 -0
- package/package.json +178 -4
- package/schemas/certification.schema.json +59 -0
- package/schemas/corrections.schema.json +29 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.candidateInstants = candidateInstants;
|
|
4
|
+
/**
|
|
5
|
+
* The methods, run for a place and a civil date (month 0-based, as the
|
|
6
|
+
* methods count): the authority's own formula, then its correction list.
|
|
7
|
+
* This is the computation `timesFor` and the checks share; the API around
|
|
8
|
+
* it is in `api.ts`.
|
|
9
|
+
*/
|
|
10
|
+
const sweden_js_1 = require("../methods/sweden.js");
|
|
11
|
+
const morocco_js_1 = require("../methods/morocco.js");
|
|
12
|
+
const algeria_js_1 = require("../methods/algeria.js");
|
|
13
|
+
const indonesia_js_1 = require("../methods/indonesia.js");
|
|
14
|
+
const registry_js_1 = require("./registry.js");
|
|
15
|
+
const clock_js_1 = require("./clock.js");
|
|
16
|
+
/**
|
|
17
|
+
* The method as it stands, certified or not, for a civil date with the
|
|
18
|
+
* month 0-based. Null where the method gives no times for the day. Not for
|
|
19
|
+
* showing anyone their prayer times: `timesFor` is.
|
|
20
|
+
*/
|
|
21
|
+
function candidateInstants(place, year, month, day, asrShadow = 1, opts = {}) {
|
|
22
|
+
const fix = opts.corrections === false ? null : (0, registry_js_1.authorityData)(place.authority).corrections;
|
|
23
|
+
switch (place.authority) {
|
|
24
|
+
case 'sweden':
|
|
25
|
+
case 'diyanet': {
|
|
26
|
+
// The Congress method's own rounding is inside it; its instants land on the minute (rounded, as the app does).
|
|
27
|
+
const clock = (0, clock_js_1.placeClockAt)(place, year, month, day);
|
|
28
|
+
const t = place.prayerPoints ? perPrayer(place, place.prayerPoints, year, month, day, asrShadow) : (0, sweden_js_1.congressTimes)(place.lat, place.lon, year, month, day, asrShadow, place.ishaDeg, clock);
|
|
29
|
+
// then the correction list: the few times Diyanet's program rounds the other way (the standard Asr only)
|
|
30
|
+
const c = fix?.correction(place.lat, place.lon, year, month, day);
|
|
31
|
+
const min = (d, k) => new Date((Math.round(d.getTime() / 60_000) + (k === 'asr' && asrShadow !== 1 ? 0 : (c?.[k] ?? 0))) * 60_000);
|
|
32
|
+
return { fajr: min(t.fajr, 'fajr'), sunrise: min(t.sunrise, 'sunrise'), dhuhr: min(t.dhuhr, 'dhuhr'), asr: min(t.asr, 'asr'), maghrib: min(t.maghrib, 'maghrib'), isha: min(t.isha, 'isha') };
|
|
33
|
+
}
|
|
34
|
+
case 'morocco':
|
|
35
|
+
case 'algeria':
|
|
36
|
+
case 'indonesia': {
|
|
37
|
+
const t = place.authority === 'morocco'
|
|
38
|
+
? (0, morocco_js_1.moroccoTimes)(place.lat, place.lon, year, month, day, place.dipDeg ?? 0, asrShadow, place.dipMaghribDeg)
|
|
39
|
+
: place.authority === 'algeria'
|
|
40
|
+
? (0, algeria_js_1.algeriaTimes)(place.lat, place.lon, year, month, day, asrShadow)
|
|
41
|
+
: (0, indonesia_js_1.kemenagTimes)(place.lat, place.lon, year, month, day, { highland: place.highland, twilightDip: place.twilightDip, asrShadow, afternoon: place.afternoon });
|
|
42
|
+
// the correction list: the authority's few times on the other side of a minute (the standard Asr only)
|
|
43
|
+
const c = !t || !fix ? undefined : fix.correction(place.lat, place.lon, year, month, day);
|
|
44
|
+
if (!t || !c)
|
|
45
|
+
return t;
|
|
46
|
+
const mv = (d, k) => new Date(d.getTime() + (k === 'asr' && asrShadow !== 1 ? 0 : (c[k] ?? 0)) * 60_000);
|
|
47
|
+
return { fajr: mv(t.fajr, 'fajr'), sunrise: mv(t.sunrise, 'sunrise'), dhuhr: mv(t.dhuhr, 'dhuhr'), asr: mv(t.asr, 'asr'), maghrib: mv(t.maghrib, 'maghrib'), isha: mv(t.isha, 'isha') };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Türkiye's districts: each prayer at its own point for the year (the nearest year's beyond the tables). */
|
|
52
|
+
function perPrayer(place, pts, year, month, day, asrShadow) {
|
|
53
|
+
const years = Object.keys(pts).map(Number).sort((a, b) => a - b);
|
|
54
|
+
const y = years.reduce((b, v) => (Math.abs(v - year) < Math.abs(b - year) ? v : b), years[0]);
|
|
55
|
+
const p = pts[String(y)];
|
|
56
|
+
const clock = (0, clock_js_1.placeClockAt)(place, year, month, day);
|
|
57
|
+
const at = (i) => (0, sweden_js_1.congressTimes)(p[i][0], p[i][1], year, month, day, asrShadow, place.ishaDeg, clock);
|
|
58
|
+
return { fajr: at(0).fajr, sunrise: at(1).sunrise, dhuhr: at(2).dhuhr, asr: at(3).asr, maghrib: at(4).maghrib, isha: at(5).isha };
|
|
59
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A correction list, indexed for lookup: point → date → the minutes to add
|
|
3
|
+
* to each printed time. Built from the embedded data (or, for the tools,
|
|
4
|
+
* from a file read into the same shape).
|
|
5
|
+
*/
|
|
6
|
+
import type { CorrectionsFile, PrayerKey } from './types.js';
|
|
7
|
+
export declare const pointKey: (lat: number, lon: number) => string;
|
|
8
|
+
export declare class CorrectionList {
|
|
9
|
+
private source;
|
|
10
|
+
private index;
|
|
11
|
+
constructor(source: CorrectionsFile);
|
|
12
|
+
private load;
|
|
13
|
+
/** The minutes to add to the point's printed times on a date (month 0-based), if any. */
|
|
14
|
+
correction(lat: number, lon: number, year: number, month: number, day: number): Partial<Record<PrayerKey, number>> | undefined;
|
|
15
|
+
coverage(): {
|
|
16
|
+
from: string;
|
|
17
|
+
to: string;
|
|
18
|
+
};
|
|
19
|
+
entries(): number;
|
|
20
|
+
file(): CorrectionsFile;
|
|
21
|
+
/** Put another list in force (a newer one for the same method revision). */
|
|
22
|
+
replace(source: CorrectionsFile): void;
|
|
23
|
+
}
|
|
24
|
+
/** A list that does not have the shape of one is refused whole. */
|
|
25
|
+
export declare function isCorrectionsFile(x: unknown): x is CorrectionsFile;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CorrectionList = exports.pointKey = void 0;
|
|
4
|
+
exports.isCorrectionsFile = isCorrectionsFile;
|
|
5
|
+
const pointKey = (lat, lon) => `${lat.toFixed(3)},${lon.toFixed(3)}`;
|
|
6
|
+
exports.pointKey = pointKey;
|
|
7
|
+
class CorrectionList {
|
|
8
|
+
source;
|
|
9
|
+
index = null;
|
|
10
|
+
constructor(source) {
|
|
11
|
+
this.source = source;
|
|
12
|
+
}
|
|
13
|
+
load() {
|
|
14
|
+
if (this.index)
|
|
15
|
+
return this.index;
|
|
16
|
+
const index = new Map();
|
|
17
|
+
for (const [point, list] of Object.entries(this.source.points)) {
|
|
18
|
+
const byDate = new Map();
|
|
19
|
+
for (const e of list) {
|
|
20
|
+
const [date, key, step] = e.split(' ');
|
|
21
|
+
const c = byDate.get(date) ?? {};
|
|
22
|
+
c[key] = Number(step);
|
|
23
|
+
byDate.set(date, c);
|
|
24
|
+
}
|
|
25
|
+
index.set(point, byDate);
|
|
26
|
+
}
|
|
27
|
+
return (this.index = index);
|
|
28
|
+
}
|
|
29
|
+
/** The minutes to add to the point's printed times on a date (month 0-based), if any. */
|
|
30
|
+
correction(lat, lon, year, month, day) {
|
|
31
|
+
const date = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
|
32
|
+
return this.load().get((0, exports.pointKey)(lat, lon))?.get(date);
|
|
33
|
+
}
|
|
34
|
+
coverage() {
|
|
35
|
+
return { from: this.source.from, to: this.source.to };
|
|
36
|
+
}
|
|
37
|
+
entries() {
|
|
38
|
+
return Object.values(this.source.points).reduce((n, e) => n + e.length, 0);
|
|
39
|
+
}
|
|
40
|
+
file() {
|
|
41
|
+
return this.source;
|
|
42
|
+
}
|
|
43
|
+
/** Put another list in force (a newer one for the same method revision). */
|
|
44
|
+
replace(source) {
|
|
45
|
+
this.source = source;
|
|
46
|
+
this.index = null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.CorrectionList = CorrectionList;
|
|
50
|
+
/** A list that does not have the shape of one is refused whole. */
|
|
51
|
+
function isCorrectionsFile(x) {
|
|
52
|
+
if (!x || typeof x !== 'object')
|
|
53
|
+
return false;
|
|
54
|
+
const c = x;
|
|
55
|
+
const date = /^\d{4}-\d{2}-\d{2}$/;
|
|
56
|
+
if (typeof c.from !== 'string' || typeof c.to !== 'string' || !date.test(c.from) || !date.test(c.to) || c.from > c.to)
|
|
57
|
+
return false;
|
|
58
|
+
if (!c.points || typeof c.points !== 'object')
|
|
59
|
+
return false;
|
|
60
|
+
const entry = /^\d{4}-\d{2}-\d{2} (fajr|sunrise|dhuhr|asr|maghrib|isha) [+-]1$/;
|
|
61
|
+
return Object.entries(c.points).every(([k, v]) => /^-?\d+\.\d{3},-?\d+\.\d{3}$/.test(k) && Array.isArray(v) && v.every(e => typeof e === 'string' && entry.test(e)));
|
|
62
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Authority, CorrectionsFile } from './types.js';
|
|
2
|
+
/** Where the feed lives. A tagged release (`.../v1.2.0/...`) can replace `main` for a pinned address. */
|
|
3
|
+
export declare const DEFAULT_FEED_URL = "https://raw.githubusercontent.com/MihrabHQ/mihrab-methods/main";
|
|
4
|
+
export type FetchOptions = {
|
|
5
|
+
authority: Authority;
|
|
6
|
+
/** The revision this build computes; default: the loaded method's. */
|
|
7
|
+
revision?: number;
|
|
8
|
+
/** The feed's base URL (default `DEFAULT_FEED_URL`): `<base>/certification.json`, `<base>/data/corrections/<authority>.json`. */
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
/** The fetch to use (default: the global one). */
|
|
11
|
+
fetch?: typeof fetch;
|
|
12
|
+
/** SHA-256 of a UTF-8 string as lowercase hex; default: WebCrypto where there is one, else a built-in digest. */
|
|
13
|
+
sha256?: (text: string) => Promise<string>;
|
|
14
|
+
/** Put a newer list in force in this process (default true). */
|
|
15
|
+
apply?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export type ListSummary = {
|
|
18
|
+
from: string;
|
|
19
|
+
to: string;
|
|
20
|
+
entries: number;
|
|
21
|
+
};
|
|
22
|
+
export type FetchResult =
|
|
23
|
+
/** The certification names the list this build already has (or an older one). */
|
|
24
|
+
{
|
|
25
|
+
status: 'current';
|
|
26
|
+
have: ListSummary;
|
|
27
|
+
certified: boolean;
|
|
28
|
+
}
|
|
29
|
+
/** A newer list for this revision: its contents, and whether the hash matched (or could not be checked). */
|
|
30
|
+
| {
|
|
31
|
+
status: 'updated';
|
|
32
|
+
list: CorrectionsFile;
|
|
33
|
+
summary: ListSummary;
|
|
34
|
+
integrity: 'verified' | 'unchecked';
|
|
35
|
+
applied: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** The method itself has moved on: its lists no longer fit this build, which should be updated. */
|
|
38
|
+
| {
|
|
39
|
+
status: 'method-moved';
|
|
40
|
+
remoteRevision: number;
|
|
41
|
+
have: ListSummary;
|
|
42
|
+
}
|
|
43
|
+
/** The authority has published tables the method is not yet certified on: keep the list in force. */
|
|
44
|
+
| {
|
|
45
|
+
status: 'uncertified';
|
|
46
|
+
have: ListSummary;
|
|
47
|
+
}
|
|
48
|
+
/** Something did not add up (a list not matching what the certification names, a bad hash): nothing taken. */
|
|
49
|
+
| {
|
|
50
|
+
status: 'rejected';
|
|
51
|
+
reason: string;
|
|
52
|
+
have: ListSummary;
|
|
53
|
+
};
|
|
54
|
+
export declare function summarize(list: CorrectionsFile): ListSummary;
|
|
55
|
+
/** UTF-8 bytes of a string, without TextEncoder (not every runtime has it). */
|
|
56
|
+
export declare function utf8(text: string): Uint8Array;
|
|
57
|
+
/** SHA-256 (FIPS 180-4) of bytes. */
|
|
58
|
+
export declare function sha256(data: Uint8Array): Uint8Array;
|
|
59
|
+
/** Put a list in force for the process — one verified by `fetchLatestCorrections`, or restored from the app's own storage. */
|
|
60
|
+
export declare function applyCorrections(authority: Authority, list: CorrectionsFile, revision: number): boolean;
|
|
61
|
+
export declare function fetchLatestCorrections(opts: FetchOptions): Promise<FetchResult>;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_FEED_URL = void 0;
|
|
4
|
+
exports.summarize = summarize;
|
|
5
|
+
exports.utf8 = utf8;
|
|
6
|
+
exports.sha256 = sha256;
|
|
7
|
+
exports.applyCorrections = applyCorrections;
|
|
8
|
+
exports.fetchLatestCorrections = fetchLatestCorrections;
|
|
9
|
+
/**
|
|
10
|
+
* Keeping an app current without a release: the repository publishes
|
|
11
|
+
* `certification.json` and the correction lists it certifies, and an app
|
|
12
|
+
* that computes a method's revision can take any newer list certified for
|
|
13
|
+
* that revision. This is the check done right — the revision, the list's
|
|
14
|
+
* identity, and its SHA-256 as the certification names it.
|
|
15
|
+
*/
|
|
16
|
+
const registry_js_1 = require("./registry.js");
|
|
17
|
+
const correctionList_js_1 = require("./correctionList.js");
|
|
18
|
+
/** Where the feed lives. A tagged release (`.../v1.2.0/...`) can replace `main` for a pinned address. */
|
|
19
|
+
exports.DEFAULT_FEED_URL = 'https://raw.githubusercontent.com/MihrabHQ/mihrab-methods/main';
|
|
20
|
+
function summarize(list) {
|
|
21
|
+
return { from: list.from, to: list.to, entries: Object.values(list.points).reduce((n, e) => n + e.length, 0) };
|
|
22
|
+
}
|
|
23
|
+
const same = (a, b) => a.from === b.from && a.to === b.to && a.entries === b.entries;
|
|
24
|
+
/**
|
|
25
|
+
* SHA-256 as lowercase hex. WebCrypto where the runtime has it (browsers,
|
|
26
|
+
* Node 18+, Deno, Bun); elsewhere — Hermes in React Native has none — the
|
|
27
|
+
* plain-JavaScript digest below. No `node:crypto` import: a bundler for a
|
|
28
|
+
* phone or a browser fails on the import itself, used or not.
|
|
29
|
+
*/
|
|
30
|
+
async function defaultSha256(text) {
|
|
31
|
+
const bytes = utf8(text);
|
|
32
|
+
const subtle = globalThis.crypto?.subtle;
|
|
33
|
+
if (subtle) {
|
|
34
|
+
try {
|
|
35
|
+
const buf = await subtle.digest('SHA-256', bytes);
|
|
36
|
+
return hex(new Uint8Array(buf));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
/* a subtle that refuses (an insecure context): the digest below */
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return hex(sha256(bytes));
|
|
43
|
+
}
|
|
44
|
+
const hex = (b) => Array.from(b, x => x.toString(16).padStart(2, '0')).join('');
|
|
45
|
+
/** UTF-8 bytes of a string, without TextEncoder (not every runtime has it). */
|
|
46
|
+
function utf8(text) {
|
|
47
|
+
const out = [];
|
|
48
|
+
for (let i = 0; i < text.length; i++) {
|
|
49
|
+
let c = text.charCodeAt(i);
|
|
50
|
+
if (c >= 0xd800 && c < 0xdc00 && i + 1 < text.length) {
|
|
51
|
+
const d = text.charCodeAt(i + 1);
|
|
52
|
+
if (d >= 0xdc00 && d < 0xe000) {
|
|
53
|
+
c = 0x10000 + ((c - 0xd800) << 10) + (d - 0xdc00);
|
|
54
|
+
i++;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (c < 0x80)
|
|
58
|
+
out.push(c);
|
|
59
|
+
else if (c < 0x800)
|
|
60
|
+
out.push(0xc0 | (c >> 6), 0x80 | (c & 63));
|
|
61
|
+
else if (c < 0x10000)
|
|
62
|
+
out.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 63), 0x80 | (c & 63));
|
|
63
|
+
else
|
|
64
|
+
out.push(0xf0 | (c >> 18), 0x80 | ((c >> 12) & 63), 0x80 | ((c >> 6) & 63), 0x80 | (c & 63));
|
|
65
|
+
}
|
|
66
|
+
return Uint8Array.from(out);
|
|
67
|
+
}
|
|
68
|
+
const K = new Uint32Array([
|
|
69
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
70
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
71
|
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
72
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
73
|
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
74
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
75
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
76
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
77
|
+
]);
|
|
78
|
+
/** SHA-256 (FIPS 180-4) of bytes. */
|
|
79
|
+
function sha256(data) {
|
|
80
|
+
const bitLen = data.length * 8;
|
|
81
|
+
const padded = new Uint8Array(((data.length + 9 + 63) >> 6) << 6);
|
|
82
|
+
padded.set(data);
|
|
83
|
+
padded[data.length] = 0x80;
|
|
84
|
+
const view = new DataView(padded.buffer);
|
|
85
|
+
view.setUint32(padded.length - 8, Math.floor(bitLen / 0x100000000));
|
|
86
|
+
view.setUint32(padded.length - 4, bitLen >>> 0);
|
|
87
|
+
const h = new Uint32Array([0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]);
|
|
88
|
+
const w = new Uint32Array(64);
|
|
89
|
+
const rotr = (x, n) => (x >>> n) | (x << (32 - n));
|
|
90
|
+
for (let off = 0; off < padded.length; off += 64) {
|
|
91
|
+
for (let i = 0; i < 16; i++)
|
|
92
|
+
w[i] = view.getUint32(off + i * 4);
|
|
93
|
+
for (let i = 16; i < 64; i++) {
|
|
94
|
+
const s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >>> 3);
|
|
95
|
+
const s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >>> 10);
|
|
96
|
+
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0;
|
|
97
|
+
}
|
|
98
|
+
let [a, b, c, d, e, f, g, hh] = h;
|
|
99
|
+
for (let i = 0; i < 64; i++) {
|
|
100
|
+
const t1 = (hh + (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) + ((e & f) ^ (~e & g)) + K[i] + w[i]) >>> 0;
|
|
101
|
+
const t2 = ((rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) + ((a & b) ^ (a & c) ^ (b & c))) >>> 0;
|
|
102
|
+
hh = g;
|
|
103
|
+
g = f;
|
|
104
|
+
f = e;
|
|
105
|
+
e = (d + t1) >>> 0;
|
|
106
|
+
d = c;
|
|
107
|
+
c = b;
|
|
108
|
+
b = a;
|
|
109
|
+
a = (t1 + t2) >>> 0;
|
|
110
|
+
}
|
|
111
|
+
h[0] += a;
|
|
112
|
+
h[1] += b;
|
|
113
|
+
h[2] += c;
|
|
114
|
+
h[3] += d;
|
|
115
|
+
h[4] += e;
|
|
116
|
+
h[5] += f;
|
|
117
|
+
h[6] += g;
|
|
118
|
+
h[7] += hh;
|
|
119
|
+
}
|
|
120
|
+
const out = new Uint8Array(32);
|
|
121
|
+
const ov = new DataView(out.buffer);
|
|
122
|
+
for (let i = 0; i < 8; i++)
|
|
123
|
+
ov.setUint32(i * 4, h[i]);
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
/** Put a list in force for the process — one verified by `fetchLatestCorrections`, or restored from the app's own storage. */
|
|
127
|
+
function applyCorrections(authority, list, revision) {
|
|
128
|
+
const data = (0, registry_js_1.authorityData)(authority);
|
|
129
|
+
if (revision !== data.revision || !(0, correctionList_js_1.isCorrectionsFile)(list))
|
|
130
|
+
return false;
|
|
131
|
+
const now = data.corrections.coverage();
|
|
132
|
+
if (list.to < now.to)
|
|
133
|
+
return false;
|
|
134
|
+
data.corrections.replace(list);
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
async function fetchLatestCorrections(opts) {
|
|
138
|
+
const data = (0, registry_js_1.authorityData)(opts.authority);
|
|
139
|
+
const have = { ...data.corrections.coverage(), entries: data.corrections.entries() };
|
|
140
|
+
const revision = opts.revision ?? data.revision;
|
|
141
|
+
const base = (opts.baseUrl ?? exports.DEFAULT_FEED_URL).replace(/\/+$/, '');
|
|
142
|
+
const doFetch = opts.fetch ?? globalThis.fetch;
|
|
143
|
+
if (!doFetch)
|
|
144
|
+
return { status: 'rejected', reason: 'no fetch available', have };
|
|
145
|
+
const certRes = await doFetch(`${base}/certification.json`);
|
|
146
|
+
if (!certRes.ok)
|
|
147
|
+
return { status: 'rejected', reason: `certification.json: HTTP ${certRes.status}`, have };
|
|
148
|
+
const cert = (await certRes.json());
|
|
149
|
+
const entry = cert?.[opts.authority];
|
|
150
|
+
if (!entry || typeof entry !== 'object' || typeof entry.certified !== 'boolean') {
|
|
151
|
+
return { status: 'rejected', reason: `certification.json has no entry for ${opts.authority}`, have };
|
|
152
|
+
}
|
|
153
|
+
if (typeof entry.revision === 'number' && entry.revision > revision) {
|
|
154
|
+
return { status: 'method-moved', remoteRevision: entry.revision, have };
|
|
155
|
+
}
|
|
156
|
+
if (!entry.certified)
|
|
157
|
+
return { status: 'uncertified', have };
|
|
158
|
+
if (entry.revision !== revision)
|
|
159
|
+
return { status: 'rejected', reason: `certified for revision ${entry.revision}, this build computes ${revision}`, have };
|
|
160
|
+
const named = entry.corrections;
|
|
161
|
+
if (!named || typeof named.from !== 'string' || typeof named.to !== 'string' || typeof named.entries !== 'number') {
|
|
162
|
+
return { status: 'rejected', reason: 'the certification names no correction list', have };
|
|
163
|
+
}
|
|
164
|
+
if (same(have, named) || named.to < have.to)
|
|
165
|
+
return { status: 'current', have, certified: true };
|
|
166
|
+
const listRes = await doFetch(`${base}/data/corrections/${opts.authority}.json`);
|
|
167
|
+
if (!listRes.ok)
|
|
168
|
+
return { status: 'rejected', reason: `${opts.authority}.json: HTTP ${listRes.status}`, have };
|
|
169
|
+
const text = await listRes.text();
|
|
170
|
+
let list;
|
|
171
|
+
try {
|
|
172
|
+
list = JSON.parse(text);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return { status: 'rejected', reason: 'the list is not JSON', have };
|
|
176
|
+
}
|
|
177
|
+
if (!(0, correctionList_js_1.isCorrectionsFile)(list))
|
|
178
|
+
return { status: 'rejected', reason: 'the list does not have the shape of one', have };
|
|
179
|
+
const summary = summarize(list);
|
|
180
|
+
if (!same(summary, named))
|
|
181
|
+
return { status: 'rejected', reason: 'the list is not the one the certification names', have };
|
|
182
|
+
// A certification without a hash (one written before 1.0.0) is taken on its identity alone.
|
|
183
|
+
let integrity = 'unchecked';
|
|
184
|
+
if (named.sha256) {
|
|
185
|
+
const hash = opts.sha256 ? await opts.sha256(text) : await defaultSha256(text);
|
|
186
|
+
if (hash.toLowerCase() !== named.sha256.toLowerCase())
|
|
187
|
+
return { status: 'rejected', reason: 'the list’s SHA-256 is not the one the certification names', have };
|
|
188
|
+
integrity = 'verified';
|
|
189
|
+
}
|
|
190
|
+
const applied = opts.apply === false ? false : applyCorrections(opts.authority, list, revision);
|
|
191
|
+
return { status: 'updated', list, summary, integrity, applied };
|
|
192
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The library without any authority's data: the calls, the types, the sun.
|
|
3
|
+
* Load an authority (`mihrab-methods/<authority>`, or `mihrab-methods` for
|
|
4
|
+
* all) before calling anything that needs its places or its list.
|
|
5
|
+
*/
|
|
6
|
+
export { candidateTimes, certificationOf, certifiedSpan, distanceKm, isCertified, loadedAuthorityIds, methodInfo, nearestPlace, placeById, placesOf, timesFor, timesForRange, type NearestPlace, } from './api.js';
|
|
7
|
+
export { candidateInstants, type ComputeOptions } from './compute.js';
|
|
8
|
+
export { parseCivilDate, isoOf } from './civilDate.js';
|
|
9
|
+
export { placeClockAt, clockOffsetAt, tableClockAt, printedAt } from './clock.js';
|
|
10
|
+
export { fetchLatestCorrections, applyCorrections, type FetchOptions, type FetchResult } from './fetchLatest.js';
|
|
11
|
+
export { isCorrectionsFile, pointKey } from './correctionList.js';
|
|
12
|
+
export { METHOD_REVISION } from '../methods/revisions.js';
|
|
13
|
+
export { preciseApparentSun } from '../sun/preciseSun.js';
|
|
14
|
+
export { AUTHORITIES, PRAYER_KEYS, UncertifiedMethodError, type Authority, type Certification, type CheckRecord, type CivilDate, type CorrectionsFile, type DayStatus, type DayTimes, type Instants, type MethodInfo, type Place, type PrayerKey, type PrayerTime, type TableClock, type TimesOptions, } from './types.js';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UncertifiedMethodError = exports.PRAYER_KEYS = exports.AUTHORITIES = exports.preciseApparentSun = exports.METHOD_REVISION = exports.pointKey = exports.isCorrectionsFile = exports.applyCorrections = exports.fetchLatestCorrections = exports.printedAt = exports.tableClockAt = exports.clockOffsetAt = exports.placeClockAt = exports.isoOf = exports.parseCivilDate = exports.candidateInstants = exports.timesForRange = exports.timesFor = exports.placesOf = exports.placeById = exports.nearestPlace = exports.methodInfo = exports.loadedAuthorityIds = exports.isCertified = exports.distanceKm = exports.certifiedSpan = exports.certificationOf = exports.candidateTimes = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* The library without any authority's data: the calls, the types, the sun.
|
|
6
|
+
* Load an authority (`mihrab-methods/<authority>`, or `mihrab-methods` for
|
|
7
|
+
* all) before calling anything that needs its places or its list.
|
|
8
|
+
*/
|
|
9
|
+
var api_js_1 = require("./api.js");
|
|
10
|
+
Object.defineProperty(exports, "candidateTimes", { enumerable: true, get: function () { return api_js_1.candidateTimes; } });
|
|
11
|
+
Object.defineProperty(exports, "certificationOf", { enumerable: true, get: function () { return api_js_1.certificationOf; } });
|
|
12
|
+
Object.defineProperty(exports, "certifiedSpan", { enumerable: true, get: function () { return api_js_1.certifiedSpan; } });
|
|
13
|
+
Object.defineProperty(exports, "distanceKm", { enumerable: true, get: function () { return api_js_1.distanceKm; } });
|
|
14
|
+
Object.defineProperty(exports, "isCertified", { enumerable: true, get: function () { return api_js_1.isCertified; } });
|
|
15
|
+
Object.defineProperty(exports, "loadedAuthorityIds", { enumerable: true, get: function () { return api_js_1.loadedAuthorityIds; } });
|
|
16
|
+
Object.defineProperty(exports, "methodInfo", { enumerable: true, get: function () { return api_js_1.methodInfo; } });
|
|
17
|
+
Object.defineProperty(exports, "nearestPlace", { enumerable: true, get: function () { return api_js_1.nearestPlace; } });
|
|
18
|
+
Object.defineProperty(exports, "placeById", { enumerable: true, get: function () { return api_js_1.placeById; } });
|
|
19
|
+
Object.defineProperty(exports, "placesOf", { enumerable: true, get: function () { return api_js_1.placesOf; } });
|
|
20
|
+
Object.defineProperty(exports, "timesFor", { enumerable: true, get: function () { return api_js_1.timesFor; } });
|
|
21
|
+
Object.defineProperty(exports, "timesForRange", { enumerable: true, get: function () { return api_js_1.timesForRange; } });
|
|
22
|
+
var compute_js_1 = require("./compute.js");
|
|
23
|
+
Object.defineProperty(exports, "candidateInstants", { enumerable: true, get: function () { return compute_js_1.candidateInstants; } });
|
|
24
|
+
var civilDate_js_1 = require("./civilDate.js");
|
|
25
|
+
Object.defineProperty(exports, "parseCivilDate", { enumerable: true, get: function () { return civilDate_js_1.parseCivilDate; } });
|
|
26
|
+
Object.defineProperty(exports, "isoOf", { enumerable: true, get: function () { return civilDate_js_1.isoOf; } });
|
|
27
|
+
var clock_js_1 = require("./clock.js");
|
|
28
|
+
Object.defineProperty(exports, "placeClockAt", { enumerable: true, get: function () { return clock_js_1.placeClockAt; } });
|
|
29
|
+
Object.defineProperty(exports, "clockOffsetAt", { enumerable: true, get: function () { return clock_js_1.clockOffsetAt; } });
|
|
30
|
+
Object.defineProperty(exports, "tableClockAt", { enumerable: true, get: function () { return clock_js_1.tableClockAt; } });
|
|
31
|
+
Object.defineProperty(exports, "printedAt", { enumerable: true, get: function () { return clock_js_1.printedAt; } });
|
|
32
|
+
var fetchLatest_js_1 = require("./fetchLatest.js");
|
|
33
|
+
Object.defineProperty(exports, "fetchLatestCorrections", { enumerable: true, get: function () { return fetchLatest_js_1.fetchLatestCorrections; } });
|
|
34
|
+
Object.defineProperty(exports, "applyCorrections", { enumerable: true, get: function () { return fetchLatest_js_1.applyCorrections; } });
|
|
35
|
+
var correctionList_js_1 = require("./correctionList.js");
|
|
36
|
+
Object.defineProperty(exports, "isCorrectionsFile", { enumerable: true, get: function () { return correctionList_js_1.isCorrectionsFile; } });
|
|
37
|
+
Object.defineProperty(exports, "pointKey", { enumerable: true, get: function () { return correctionList_js_1.pointKey; } });
|
|
38
|
+
var revisions_js_1 = require("../methods/revisions.js");
|
|
39
|
+
Object.defineProperty(exports, "METHOD_REVISION", { enumerable: true, get: function () { return revisions_js_1.METHOD_REVISION; } });
|
|
40
|
+
var preciseSun_js_1 = require("../sun/preciseSun.js");
|
|
41
|
+
Object.defineProperty(exports, "preciseApparentSun", { enumerable: true, get: function () { return preciseSun_js_1.preciseApparentSun; } });
|
|
42
|
+
var types_js_1 = require("./types.js");
|
|
43
|
+
Object.defineProperty(exports, "AUTHORITIES", { enumerable: true, get: function () { return types_js_1.AUTHORITIES; } });
|
|
44
|
+
Object.defineProperty(exports, "PRAYER_KEYS", { enumerable: true, get: function () { return types_js_1.PRAYER_KEYS; } });
|
|
45
|
+
Object.defineProperty(exports, "UncertifiedMethodError", { enumerable: true, get: function () { return types_js_1.UncertifiedMethodError; } });
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What each authority's entry point brings: its places, its correction
|
|
3
|
+
* list, its certification and its description. `mihrab-methods/indonesia`
|
|
4
|
+
* registers Indonesia and nothing else, so an app ships only the data it
|
|
5
|
+
* uses; `mihrab-methods` registers all five.
|
|
6
|
+
*/
|
|
7
|
+
import type { Authority, Certification, CorrectionsFile, MethodInfo, Place } from './types.js';
|
|
8
|
+
import { CorrectionList } from './correctionList.js';
|
|
9
|
+
export type MethodDescription = Pick<MethodInfo, 'name' | 'method' | 'countries' | 'parameters' | 'sources' | 'spec'>;
|
|
10
|
+
export type AuthorityData = {
|
|
11
|
+
authority: Authority;
|
|
12
|
+
revision: number;
|
|
13
|
+
places: readonly Place[];
|
|
14
|
+
corrections: CorrectionList;
|
|
15
|
+
certification: Certification | null;
|
|
16
|
+
description: MethodDescription;
|
|
17
|
+
};
|
|
18
|
+
export declare function registerAuthority(entry: {
|
|
19
|
+
authority: Authority;
|
|
20
|
+
revision: number;
|
|
21
|
+
places: Place[];
|
|
22
|
+
corrections: CorrectionsFile;
|
|
23
|
+
certification: Certification | null;
|
|
24
|
+
description: MethodDescription;
|
|
25
|
+
}): AuthorityData;
|
|
26
|
+
export declare function authorityData(authority: Authority): AuthorityData;
|
|
27
|
+
export declare function loadedAuthorities(): Authority[];
|
|
28
|
+
export declare function isLoaded(authority: Authority): boolean;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerAuthority = registerAuthority;
|
|
4
|
+
exports.authorityData = authorityData;
|
|
5
|
+
exports.loadedAuthorities = loadedAuthorities;
|
|
6
|
+
exports.isLoaded = isLoaded;
|
|
7
|
+
const correctionList_js_1 = require("./correctionList.js");
|
|
8
|
+
const registry = new Map();
|
|
9
|
+
function registerAuthority(entry) {
|
|
10
|
+
const have = registry.get(entry.authority);
|
|
11
|
+
if (have)
|
|
12
|
+
return have;
|
|
13
|
+
// Frozen: every caller shares these objects, and a place moved by one
|
|
14
|
+
// (`place.lat = …`) would move the corrections it is looked up by for all.
|
|
15
|
+
for (const p of entry.places)
|
|
16
|
+
Object.freeze(p);
|
|
17
|
+
Object.freeze(entry.places);
|
|
18
|
+
const data = { ...entry, corrections: new correctionList_js_1.CorrectionList(entry.corrections) };
|
|
19
|
+
registry.set(entry.authority, data);
|
|
20
|
+
return data;
|
|
21
|
+
}
|
|
22
|
+
function authorityData(authority) {
|
|
23
|
+
const data = registry.get(authority);
|
|
24
|
+
if (!data) {
|
|
25
|
+
throw new Error(`The ${authority} method is not loaded: import 'mihrab-methods/${authority}' (or 'mihrab-methods' for all of them) first.`);
|
|
26
|
+
}
|
|
27
|
+
return data;
|
|
28
|
+
}
|
|
29
|
+
function loadedAuthorities() {
|
|
30
|
+
return [...registry.keys()];
|
|
31
|
+
}
|
|
32
|
+
function isLoaded(authority) {
|
|
33
|
+
return registry.has(authority);
|
|
34
|
+
}
|