panchang-ts 0.2.2 → 0.3.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/README.md CHANGED
@@ -11,9 +11,13 @@ Works offline in React Native (Hermes), Node.js, and browsers.
11
11
  - **Muhurta:** Brahma Muhurta, Abhijit Muhurta
12
12
  - **Inauspicious periods:** Rahu Kalam, Gulika Kalam, Yamaganda
13
13
  - **Choghadiya:** 16 time slots (8 day + 8 night), each named and rated auspicious/neutral/inauspicious
14
+ - **Gowri Panchangam:** 16 Gowri Nalla Neram slots (8 day + 8 night) with 8-name cycle, vara-based starting index
14
15
  - **Hora:** 24 planetary hours per day (12 day + 12 night) in Chaldean order
15
16
  - **Astronomical events:** Sunrise, Sunset, Moonrise, Moonset
16
17
  - **Panchaka detection:** Flag when Moon is in the last 5 nakshatras (Dhanishta 3rd pada → Revati)
18
+ - **Special Yogas:** Amrit Siddhi, Sarvartha Siddhi, Ravi Pushya, Guru Pushya — detected from Vara × Tithi/Nakshatra tables
19
+ - **Dur Muhurta:** Two ~48-minute inauspicious windows per day, position varies by Vara
20
+ - **Festival detection:** 24 major pan-Indian festivals, recurring Ekadashi & Pradosha Vrata, Sankranti; skips Adhika (leap) months automatically
17
21
  - **Daily mode:** Full sunrise-to-sunrise day with all element transitions
18
22
  - **Instant mode:** Elements active at an exact moment (birth charts, muhurta selection)
19
23
  - **3 ayanamsa systems:** Lahiri (default), B.V. Raman, KP (Krishnamurti)
@@ -72,6 +76,28 @@ result.choghadiya.day.forEach(slot => {
72
76
 
73
77
  // Panchaka
74
78
  console.log(result.panchaka); // true | false
79
+
80
+ // Special Yogas active today
81
+ result.specialYogas.forEach(yoga => {
82
+ console.log(yoga.name, yoga.type); // "Guru Pushya Yoga", "guru_pushya"
83
+ });
84
+
85
+ // Dur Muhurta — two inauspicious windows
86
+ const [dm1, dm2] = result.durMuhurta;
87
+ console.log(fmt(dm1.start), '-', fmt(dm1.end)); // e.g. "11:36 - 12:24"
88
+ console.log(fmt(dm2.start), '-', fmt(dm2.end));
89
+
90
+ // Festivals today
91
+ result.festivals.forEach(f => {
92
+ console.log(f.name, f.type); // "Diwali", "major"
93
+ });
94
+
95
+ // Gowri Panchangam — 8 daytime slots
96
+ result.gowriPanchangam.day.forEach(slot => {
97
+ console.log(slot.name, slot.quality); // "Amrit", "auspicious"
98
+ });
99
+
100
+
75
101
  ```
76
102
 
77
103
  ## Reading Output Times
@@ -137,17 +163,22 @@ const result = getDailyPanchang(
137
163
  | `gulikaKalam` | `TimePeriod` | Gulika Kalam start/end |
138
164
  | `yamaganda` | `TimePeriod` | Yamaganda start/end |
139
165
  | `abhijitMuhurta` | `TimePeriod` | Abhijit Muhurta start/end |
140
- | `brahmaMuhurta` | `TimePeriod` | Brahma Muhurta (9648 min before sunrise) |
166
+ | `brahmaMuhurta` | `TimePeriod` | Brahma Muhurta — two muhurtas (dayDuration/30 each) before sunrise; ends one muhurta before sunrise (≈ 4824 min window for typical 12-h days) |
141
167
  | `masa` | `MasaInfo` | Solar month (Saura Masa) |
142
168
  | `chandramasa` | `ChandraMasaInfo` | Lunar month + Adhika (leap) flag |
143
169
  | `samvat` | `SamvatInfo` | Vikram Samvat and Shaka Samvat year numbers |
144
170
  | `chandraRashi` | `RashiInfo` | Moon's zodiac sign (changes every ~2.5 days) |
145
171
  | `suryaNakshatra` | `RashiInfo` | Sun's nakshatra (changes every ~13–14 days) |
146
172
  | `choghadiya` | `ChoghadiyaInfo` | 8 day slots + 8 night slots, each named and rated |
173
+ | `gowriPanchangam` | `GowriInfo` | 8 day + 8 night Gowri Nalla Neram slots, each named and rated |
174
+
147
175
  | `hora` | `HoraInfo` | 12 day horas + 12 night horas, each with ruling planet |
148
176
  | `moonrise` | `Date \| null` | Moonrise (offset-adjusted); `null` if none that day |
149
177
  | `moonset` | `Date \| null` | Moonset (offset-adjusted); `null` if none that day |
150
178
  | `panchaka` | `boolean` | `true` when Moon is in last 5 nakshatras |
179
+ | `specialYogas` | `SpecialYogaInfo[]` | Auspicious yogas active today (may be empty) |
180
+ | `durMuhurta` | `[TimePeriod, TimePeriod]` | Two inauspicious ~48-min windows |
181
+ | `festivals` | `FestivalInfo[]` | Festivals / observances today (may be empty) |
151
182
  | `ayanamsa` | `number` | Ayanamsa in degrees at sunrise |
152
183
  | `siderealSunAtSunrise` | `number` | Sun sidereal longitude at sunrise (°) |
153
184
  | `siderealMoonAtSunrise` | `number` | Moon sidereal longitude at sunrise (°) |
@@ -191,6 +222,8 @@ console.log(result.panchaka); // false
191
222
  | `chandraRashi` | `RashiInfo` | Moon's zodiac sign |
192
223
  | `suryaNakshatra` | `RashiInfo` | Sun's nakshatra |
193
224
  | `panchaka` | `boolean` | `true` when Moon is in last 5 nakshatras |
225
+ | `specialYogas` | `SpecialYogaInfo[]` | Auspicious yogas at this moment (may be empty) |
226
+ | `festivals` | `FestivalInfo[]` | Festivals / observances at this moment (may be empty) |
194
227
  | `ayanamsa` | `number` | Ayanamsa in degrees |
195
228
  | `siderealSun` | `number` | Sun sidereal longitude (°) |
196
229
  | `siderealMoon` | `number` | Moon sidereal longitude (°) |
@@ -205,7 +238,7 @@ console.log(result.panchaka); // false
205
238
  |--------|------|---------|-------------|
206
239
  | `timezone` | `number \| string` | **required** | UTC offset in minutes (330 for IST). Use a number on Hermes — IANA strings require `Intl`. |
207
240
  | `ayanamsa` | `'lahiri' \| 'raman' \| 'krishnamurti'` | `'lahiri'` | Ayanamsa system |
208
- | `language` | `'en' \| 'sa' \| 'hi'` | `'en'` | Language for element names |
241
+ | `language` | `'en' \| 'sa' \| 'hi'` | `'en'` | Language for element names. `'hi'` currently uses the same Devanagari names as `'sa'`. |
209
242
  | `computeEndTimes` | `boolean` | `true` | Set `false` for ~5× faster, names-only output |
210
243
  | `precision` | `'standard' \| 'high'` | `'standard'` | Binary-search iterations (15 vs 25). High precision is rarely needed. |
211
244
 
@@ -225,6 +258,7 @@ import {
225
258
  getAyanamsa,
226
259
  computeRahuKalam, computeGulikaKalam, computeYamaganda,
227
260
  computeAbhijitMuhurta, computeBrahmaMuhurta,
261
+ computeGowriPanchangam,
228
262
  } from 'panchang-ts';
229
263
 
230
264
  // Sunrise/sunset
@@ -248,8 +282,16 @@ const gulika = computeGulikaKalam(sunrise, sunset, varaIndex);
248
282
  const yama = computeYamaganda(sunrise, sunset, varaIndex);
249
283
 
250
284
  // Muhurta
251
- const abhijit = computeAbhijitMuhurta(sunrise, sunset); // { start, end }
252
- const brahma = computeBrahmaMuhurta(sunrise, sunset); // { start, end }
285
+ const abhijit = computeAbhijitMuhurta(sunrise, sunset); // { start, end }
286
+ const brahma = computeBrahmaMuhurta(sunrise, sunset); // { start, end }
287
+
288
+
289
+ // Gowri Panchangam (varaIndex: 0=Sun … 6=Sat)
290
+ const gowri = computeGowriPanchangam(sunrise, sunset, nextSunrise, varaIndex,
291
+ (i) => ['Udyog','Amrit','Roga','Laabh','Shubh','Kaal','Dhan','Chal'][i]!,
292
+ );
293
+ // gowri.day → 8 GowriSlot (sunrise → sunset)
294
+ // gowri.night → 8 GowriSlot (sunset → next sunrise)
253
295
  ```
254
296
 
255
297
  ---
@@ -289,12 +331,15 @@ interface NakshatraInfo {
289
331
  }
290
332
 
291
333
  interface DailyTithiInfo extends TithiInfo {
292
- startTime: Date | null; // null if active at sunrise
293
- isActiveAtSunrise: boolean;
334
+ startTime: Date | null; // null when isActiveAtSunrise is true (element was already active at sunrise)
335
+ isActiveAtSunrise: boolean; // true → this element was present at sunrise; false → it started mid-day (startTime is set)
294
336
  }
295
337
 
296
338
  // DailyNakshatraInfo, DailyYogaInfo, DailyKaranaInfo follow the same pattern
297
339
 
340
+ // Note: endTime and startTime are null on ALL daily elements when computeEndTimes: false.
341
+ // completionPercentage: 0 = just started, 100 = about to end (computed at sunrise moment).
342
+
298
343
  // ── Lunar calendar ───────────────────────────────────────────────────────────
299
344
 
300
345
  interface ChandraMasaInfo {
@@ -321,9 +366,9 @@ interface RashiInfo {
321
366
 
322
367
  interface VaraInfo {
323
368
  index: number; // 0 = Sunday … 6 = Saturday
324
- name: string; // e.g. "Ravivara"
325
- shortName: string; // e.g. "Sun"
326
- englishName: string; // e.g. "Sunday"
369
+ name: string; // e.g. "Ravivara" (localized full name)
370
+ shortName: string; // e.g. "Ravi" (localized short form, Sanskrit by default)
371
+ englishName: string; // e.g. "Sunday" (always English, locale-independent)
327
372
  }
328
373
 
329
374
  interface MasaInfo {
@@ -354,17 +399,51 @@ interface ChoghadiyaInfo {
354
399
  night: ChoghadiyaSlot[]; // 8 slots (sunset → next sunrise)
355
400
  }
356
401
 
402
+ // ── Gowri Panchangam ─────────────────────────────────────────────────────────
403
+
404
+ interface GowriSlot extends TimePeriod {
405
+ index: number; // 0–7 within the 8-name cycle
406
+ name: string; // e.g. "Amrit", "Kaal", "Shubh"
407
+ quality: ChoghadiyaQuality;
408
+ }
409
+
410
+ interface GowriInfo {
411
+ day: GowriSlot[]; // 8 slots (sunrise → sunset)
412
+ night: GowriSlot[]; // 8 slots (sunset → next sunrise)
413
+ }
414
+
357
415
  // ── Hora ─────────────────────────────────────────────────────────────────────
358
416
 
359
417
  interface HoraSlot extends TimePeriod {
360
- planet: string; // "Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"
361
- planetIndex: number; // 0–6 in Chaldean order
418
+ planet: string; // Chaldean order: "Sun"(0), "Venus"(1), "Mercury"(2), "Moon"(3), "Saturn"(4), "Jupiter"(5), "Mars"(6)
419
+ planetIndex: number; // 0–6 index into the Chaldean sequence above
362
420
  }
363
421
 
364
422
  interface HoraInfo {
365
423
  day: HoraSlot[]; // 12 slots (sunrise → sunset)
366
424
  night: HoraSlot[]; // 12 slots (sunset → next sunrise)
367
425
  }
426
+
427
+ // ── Special Yogas ────────────────────────────────────────────────────────────
428
+
429
+ interface SpecialYogaInfo {
430
+ name: string; // e.g. "Guru Pushya Yoga"
431
+ type: 'amrit_siddhi' | 'sarvartha_siddhi' | 'ravi_pushya' | 'guru_pushya';
432
+ }
433
+
434
+ // ── Festivals ────────────────────────────────────────────────────────────────
435
+
436
+ interface FestivalInfo {
437
+ name: string; // e.g. "Diwali", "Ekadashi"
438
+ type: 'major' | 'minor' | 'ekadashi' | 'pradosha' | 'sankranti';
439
+ description?: string; // For sankranti: "Rashi 3" — the numeric rashi index as a string; look up name from masaNames
440
+ }
441
+
442
+ // Detection rules:
443
+ // Ekadashi: both Shukla (tithi 10) and Krishna (tithi 25) pakshas
444
+ // Pradosha: Krishna Trayodashi only (tithi 27)
445
+ // Sankranti: Sun within 1° past a rashi boundary (degInRashi < 1.0)
446
+ // Fixed festivals (e.g. Diwali): matched by chandramasa index + tithi index; skipped during Adhika months
368
447
  ```
369
448
 
370
449
  ---
@@ -411,7 +490,7 @@ via the dharmSetu React Native app.
411
490
 
412
491
  ## Accuracy
413
492
 
414
- Validated against [DrikPanchang.com](https://www.drikpanchang.com) for 15+ date/city combinations.
493
+ Validated against [DrikPanchang.com](https://www.drikpanchang.com) for 19+ date/city combinations (Pune, Delhi, Chennai, Mumbai, Bangalore, New York).
415
494
 
416
495
  | Element | Accuracy |
417
496
  |---------|----------|
@@ -420,7 +499,20 @@ Validated against [DrikPanchang.com](https://www.drikpanchang.com) for 15+ date/
420
499
  | Tithi, Nakshatra, Yoga, Karana names | Exact match |
421
500
  | Element end-times | ±5 minutes |
422
501
  | Ayanamsa | ±0.005° vs Swiss Ephemeris |
423
- | Choghadiya / Hora slots | Derived from sunrise/sunset — inherits ±2 min |
502
+ | Choghadiya / Hora / Gowri slots | Derived from sunrise/sunset — inherits ±2 min |
503
+
504
+ ### Validation test suite
505
+
506
+ The test suite includes:
507
+ - **242-day structural regression** (Pune, Sep 2025 – Apr 2026): verifies no crash, correct Vara, time-ordering invariants, element counts, and all fields (including Gowri Panchangam) for every day in the window
508
+ - **19 precise-value tests** across 5 Indian cities + New York: exact Tithi name, Nakshatra name, sunrise/sunset HH:MM (±2 min tolerance), Chandra Masa name
509
+ - **10 long-range regression tests** (2030–2050): structural correctness and ayanamsa bounds for future dates
510
+
511
+ To generate fixture stubs for new date ranges (e.g. to populate against DrikPanchang):
512
+
513
+ ```bash
514
+ npx tsx scripts/generate-fixtures.ts --start 2027-01-01 --end 2027-03-31 --city Delhi
515
+ ```
424
516
 
425
517
  ---
426
518
 
@@ -454,13 +546,20 @@ try {
454
546
  ```
455
547
 
456
548
  `PanchangErrorCode` values: `INVALID_DATE`, `INVALID_LATITUDE`, `INVALID_LONGITUDE`,
457
- `INVALID_TIMEZONE`, `INVALID_AYANAMSA`, `NO_SUNRISE`, `NO_SUNSET`.
549
+ `INVALID_ELEVATION`, `INVALID_TIMEZONE`, `INVALID_AYANAMSA`, `TIMEZONE_RESOLUTION_FAILED`,
550
+ `NO_SUNRISE`, `NO_SUNSET`, `SEARCH_DIVERGED`.
458
551
 
459
552
  Note: `getMoonrise` / `getMoonset` never throw — they return `null` when no rise/set
460
553
  occurs within the search window (this is normal for the Moon).
461
554
 
462
555
  ---
463
556
 
557
+ ## Acknowledgements
558
+
559
+ - **[astronomy-engine](https://github.com/cosinekitty/astronomy)** by Don Cross — the sole runtime dependency. Provides the astronomical algorithms used for sunrise/sunset, moonrise/moonset, and planetary longitude calculations. MIT licensed.
560
+
561
+ ---
562
+
464
563
  ## License
465
564
 
466
565
  MIT
package/dist/index.cjs CHANGED
@@ -2913,6 +2913,51 @@ function computeBrahmaMuhurta(sunrise, sunset) {
2913
2913
  return { start, end };
2914
2914
  }
2915
2915
 
2916
+ // src/core/gowri.ts
2917
+ var GOWRI_QUALITY = [
2918
+ "neutral",
2919
+ // 0 Udyog
2920
+ "auspicious",
2921
+ // 1 Amrit
2922
+ "inauspicious",
2923
+ // 2 Roga
2924
+ "auspicious",
2925
+ // 3 Laabh
2926
+ "auspicious",
2927
+ // 4 Shubh
2928
+ "inauspicious",
2929
+ // 5 Kaal
2930
+ "auspicious",
2931
+ // 6 Dhan
2932
+ "neutral"
2933
+ // 7 Chal
2934
+ ];
2935
+ var DAY_START_INDEX = [6, 5, 4, 3, 2, 1, 0];
2936
+ var NIGHT_START_INDEX = [2, 1, 0, 7, 6, 5, 4];
2937
+ function buildSlots(reference, durationMs, startIndex, nameFn) {
2938
+ const slotMs = durationMs / 8;
2939
+ const slots = [];
2940
+ for (let i = 0; i < 8; i++) {
2941
+ const idx = (startIndex + i) % 8;
2942
+ slots.push({
2943
+ start: new Date(reference.getTime() + i * slotMs),
2944
+ end: new Date(reference.getTime() + (i + 1) * slotMs),
2945
+ index: idx,
2946
+ name: nameFn(idx),
2947
+ quality: GOWRI_QUALITY[idx]
2948
+ });
2949
+ }
2950
+ return slots;
2951
+ }
2952
+ function computeGowriPanchangam(sunrise, sunset, nextSunrise, varaIndex, nameFn) {
2953
+ const dayMs = sunset.getTime() - sunrise.getTime();
2954
+ const nightMs = nextSunrise.getTime() - sunset.getTime();
2955
+ return {
2956
+ day: buildSlots(sunrise, dayMs, DAY_START_INDEX[varaIndex], nameFn),
2957
+ night: buildSlots(sunset, nightMs, NIGHT_START_INDEX[varaIndex], nameFn)
2958
+ };
2959
+ }
2960
+
2916
2961
  // src/core/masa.ts
2917
2962
  var MASA_NAMES_EN = [
2918
2963
  "Mesha",
@@ -2993,9 +3038,9 @@ var CHOGHADIYA_QUALITY = [
2993
3038
  "inauspicious"
2994
3039
  // 6 Rog (Mars)
2995
3040
  ];
2996
- var DAY_START_INDEX = [0, 3, 6, 2, 5, 1, 4];
2997
- var NIGHT_START_INDEX = [5, 1, 4, 6, 0, 3, 2];
2998
- function buildSlots(reference, durationMs, startIndex, nameFn, count) {
3041
+ var DAY_START_INDEX2 = [0, 3, 6, 2, 5, 1, 4];
3042
+ var NIGHT_START_INDEX2 = [5, 1, 4, 6, 0, 3, 2];
3043
+ function buildSlots2(reference, durationMs, startIndex, nameFn, count) {
2999
3044
  const slotMs = durationMs / count;
3000
3045
  const slots = [];
3001
3046
  for (let i = 0; i < count; i++) {
@@ -3014,8 +3059,8 @@ function computeChoghadiya(sunrise, sunset, nextSunrise, varaIndex, nameFn) {
3014
3059
  const dayMs = sunset.getTime() - sunrise.getTime();
3015
3060
  const nightMs = nextSunrise.getTime() - sunset.getTime();
3016
3061
  return {
3017
- day: buildSlots(sunrise, dayMs, DAY_START_INDEX[varaIndex], nameFn, 8),
3018
- night: buildSlots(sunset, nightMs, NIGHT_START_INDEX[varaIndex], nameFn, 8)
3062
+ day: buildSlots2(sunrise, dayMs, DAY_START_INDEX2[varaIndex], nameFn, 8),
3063
+ night: buildSlots2(sunset, nightMs, NIGHT_START_INDEX2[varaIndex], nameFn, 8)
3019
3064
  };
3020
3065
  }
3021
3066
 
@@ -3051,6 +3096,164 @@ function computePanchaka(siderealMoon) {
3051
3096
  return siderealMoon >= 300;
3052
3097
  }
3053
3098
 
3099
+ // src/core/specialYogas.ts
3100
+ var AMRIT_SIDDHI_TABLE = /* @__PURE__ */ new Map([
3101
+ [0, /* @__PURE__ */ new Set([1, 4, 6, 9, 14])],
3102
+ // Sunday
3103
+ [1, /* @__PURE__ */ new Set([2, 7, 12])],
3104
+ // Monday
3105
+ [2, /* @__PURE__ */ new Set([3, 8, 13])],
3106
+ // Tuesday
3107
+ [3, /* @__PURE__ */ new Set([5, 10, 15])],
3108
+ // Wednesday
3109
+ [4, /* @__PURE__ */ new Set([6, 11])],
3110
+ // Thursday
3111
+ [5, /* @__PURE__ */ new Set([2, 7, 12])],
3112
+ // Friday
3113
+ [6, /* @__PURE__ */ new Set([3, 8, 13])]
3114
+ // Saturday
3115
+ ]);
3116
+ var SARVARTHA_SIDDHI_TABLE = /* @__PURE__ */ new Map([
3117
+ [0, /* @__PURE__ */ new Set([7, 11, 12, 20, 21, 25])],
3118
+ // Sunday: Pushya, UPhalguni, Hasta, UAshadha, Shravana, UBhadrapada
3119
+ [1, /* @__PURE__ */ new Set([3, 4, 7, 12, 16, 21])],
3120
+ // Monday: Rohini, Mrigashira, Pushya, Hasta, Anuradha, Shravana
3121
+ [2, /* @__PURE__ */ new Set([0, 2, 11, 20, 25])],
3122
+ // Tuesday: Ashwini, Krittika, UPhalguni, UAshadha, UBhadrapada
3123
+ [3, /* @__PURE__ */ new Set([1, 3, 4, 12, 16])],
3124
+ // Wednesday: Bharani, Rohini, Mrigashira, Hasta, Anuradha
3125
+ [4, /* @__PURE__ */ new Set([0, 6, 7, 14, 16, 26])],
3126
+ // Thursday: Ashwini, Punarvasu, Pushya, Swati, Anuradha, Revati
3127
+ [5, /* @__PURE__ */ new Set([0, 1, 6, 13, 21, 26])],
3128
+ // Friday: Ashwini, Bharani, Punarvasu, Chitra, Shravana, Revati
3129
+ [6, /* @__PURE__ */ new Set([3, 14, 21, 26])]
3130
+ // Saturday: Rohini, Swati, Shravana, Revati
3131
+ ]);
3132
+ function computeSpecialYogas(varaIndex, tithiIndex, nakshatraIndex, nameResolver) {
3133
+ const results = [];
3134
+ const tithiNumber = tithiIndex % 15 + 1;
3135
+ if (AMRIT_SIDDHI_TABLE.get(varaIndex)?.has(tithiNumber)) {
3136
+ results.push({ name: nameResolver("amrit_siddhi"), type: "amrit_siddhi" });
3137
+ }
3138
+ if (SARVARTHA_SIDDHI_TABLE.get(varaIndex)?.has(nakshatraIndex)) {
3139
+ results.push({ name: nameResolver("sarvartha_siddhi"), type: "sarvartha_siddhi" });
3140
+ }
3141
+ if (varaIndex === 0 && nakshatraIndex === 7) {
3142
+ results.push({ name: nameResolver("ravi_pushya"), type: "ravi_pushya" });
3143
+ }
3144
+ if (varaIndex === 4 && nakshatraIndex === 7) {
3145
+ results.push({ name: nameResolver("guru_pushya"), type: "guru_pushya" });
3146
+ }
3147
+ return results;
3148
+ }
3149
+
3150
+ // src/core/durMuhurta.ts
3151
+ var DUR_MUHURTA_INDICES = [
3152
+ [7, 13],
3153
+ // Sunday
3154
+ [3, 10],
3155
+ // Monday
3156
+ [5, 14],
3157
+ // Tuesday
3158
+ [2, 11],
3159
+ // Wednesday
3160
+ [6, 12],
3161
+ // Thursday
3162
+ [4, 9],
3163
+ // Friday
3164
+ [1, 8]
3165
+ // Saturday
3166
+ ];
3167
+ function computeDurMuhurta(sunrise, sunset, varaIndex) {
3168
+ const dayMs = sunset.getTime() - sunrise.getTime();
3169
+ const muhurtaMs = dayMs / 15;
3170
+ const sunriseMs = sunrise.getTime();
3171
+ const [idx1, idx2] = DUR_MUHURTA_INDICES[varaIndex];
3172
+ return [
3173
+ {
3174
+ start: new Date(sunriseMs + idx1 * muhurtaMs),
3175
+ end: new Date(sunriseMs + (idx1 + 1) * muhurtaMs)
3176
+ },
3177
+ {
3178
+ start: new Date(sunriseMs + idx2 * muhurtaMs),
3179
+ end: new Date(sunriseMs + (idx2 + 1) * muhurtaMs)
3180
+ }
3181
+ ];
3182
+ }
3183
+
3184
+ // src/core/festivals.ts
3185
+ var FESTIVAL_REGISTRY = [
3186
+ // Chaitra (0)
3187
+ { key: "ugadi", masa: 0, tithi: 0, type: "major" },
3188
+ { key: "rama_navami", masa: 0, tithi: 8, type: "major" },
3189
+ { key: "hanuman_jayanti", masa: 0, tithi: 14, type: "major" },
3190
+ // Vaishakha (1)
3191
+ { key: "akshaya_tritiya", masa: 1, tithi: 2, type: "major" },
3192
+ // Ashadha (3)
3193
+ { key: "guru_purnima", masa: 3, tithi: 14, type: "major" },
3194
+ // Shravana (4)
3195
+ { key: "nag_panchami", masa: 4, tithi: 4, type: "minor" },
3196
+ { key: "raksha_bandhan", masa: 4, tithi: 14, type: "major" },
3197
+ { key: "krishna_janmashtami", masa: 4, tithi: 22, type: "major" },
3198
+ // Bhadrapada (5)
3199
+ { key: "ganesh_chaturthi", masa: 5, tithi: 3, type: "major" },
3200
+ { key: "anant_chaturdashi", masa: 5, tithi: 13, type: "major" },
3201
+ // Ashwin (6)
3202
+ { key: "navaratri", masa: 6, tithi: 0, type: "major" },
3203
+ { key: "durga_ashtami", masa: 6, tithi: 7, type: "major" },
3204
+ { key: "maha_navami", masa: 6, tithi: 8, type: "major" },
3205
+ { key: "dussehra", masa: 6, tithi: 9, type: "major" },
3206
+ { key: "sharad_purnima", masa: 6, tithi: 14, type: "major" },
3207
+ // Kartika (7)
3208
+ { key: "karva_chauth", masa: 7, tithi: 18, type: "major" },
3209
+ { key: "dhanteras", masa: 7, tithi: 27, type: "major" },
3210
+ { key: "narak_chaturdashi", masa: 7, tithi: 28, type: "major" },
3211
+ { key: "diwali", masa: 7, tithi: 29, type: "major" },
3212
+ { key: "kartika_purnima", masa: 7, tithi: 14, type: "minor" },
3213
+ // Magha (10)
3214
+ { key: "vasant_panchami", masa: 10, tithi: 4, type: "major" },
3215
+ { key: "maha_shivaratri", masa: 10, tithi: 28, type: "major" },
3216
+ // Phalguna (11)
3217
+ { key: "holi", masa: 11, tithi: 14, type: "major" },
3218
+ // Bhadrapada (5) — end of Pitru Paksha
3219
+ { key: "mahalaya_amavasya", masa: 5, tithi: 29, type: "major" }
3220
+ ];
3221
+ function computeFestivals(tithiIndex, _nakshatraIndex, chandraMasaIndex, isAdhika, _varaIndex, siderealSun, nameResolver) {
3222
+ const results = [];
3223
+ if (!isAdhika) {
3224
+ for (const rule of FESTIVAL_REGISTRY) {
3225
+ if (rule.masa === chandraMasaIndex && rule.tithi === tithiIndex) {
3226
+ results.push({
3227
+ name: nameResolver(rule.key),
3228
+ type: rule.type
3229
+ });
3230
+ }
3231
+ }
3232
+ }
3233
+ if (tithiIndex === 10 || tithiIndex === 25) {
3234
+ results.push({
3235
+ name: nameResolver("ekadashi"),
3236
+ type: "ekadashi"
3237
+ });
3238
+ }
3239
+ if (tithiIndex === 27) {
3240
+ results.push({
3241
+ name: nameResolver("pradosha"),
3242
+ type: "pradosha"
3243
+ });
3244
+ }
3245
+ const degInRashi = siderealSun % 30;
3246
+ if (degInRashi < 1) {
3247
+ const rashiIndex = Math.floor(siderealSun / 30) % 12;
3248
+ results.push({
3249
+ name: nameResolver("sankranti"),
3250
+ type: "sankranti",
3251
+ description: `Rashi ${rashiIndex}`
3252
+ });
3253
+ }
3254
+ return results;
3255
+ }
3256
+
3054
3257
  // src/astronomy/moonrise.ts
3055
3258
  function getMoonrise(searchFromUtc, location, limitDays = 2) {
3056
3259
  const observer = new Observer(
@@ -3192,8 +3395,48 @@ var en = {
3192
3395
  "Phalguna"
3193
3396
  ],
3194
3397
  choghadiyaNames: ["Udveg", "Char", "Labh", "Amrit", "Kaal", "Shubh", "Rog"],
3398
+ gowriNames: ["Udyog", "Amrit", "Roga", "Laabh", "Shubh", "Kaal", "Dhan", "Chal"],
3195
3399
  grahaNames: ["Sun", "Venus", "Mercury", "Moon", "Saturn", "Jupiter", "Mars"],
3196
- misc: { purnima: "Purnima", amavasya: "Amavasya", adhika: "Adhika" }
3400
+ specialYogaNames: {
3401
+ amrit_siddhi: "Amrit Siddhi Yoga",
3402
+ sarvartha_siddhi: "Sarvartha Siddhi Yoga",
3403
+ ravi_pushya: "Ravi Pushya Yoga",
3404
+ guru_pushya: "Guru Pushya Yoga"
3405
+ },
3406
+ festivalNames: {
3407
+ ugadi: "Ugadi",
3408
+ rama_navami: "Rama Navami",
3409
+ hanuman_jayanti: "Hanuman Jayanti",
3410
+ akshaya_tritiya: "Akshaya Tritiya",
3411
+ guru_purnima: "Guru Purnima",
3412
+ nag_panchami: "Nag Panchami",
3413
+ raksha_bandhan: "Raksha Bandhan",
3414
+ krishna_janmashtami: "Krishna Janmashtami",
3415
+ ganesh_chaturthi: "Ganesh Chaturthi",
3416
+ anant_chaturdashi: "Anant Chaturdashi",
3417
+ navaratri: "Sharad Navaratri",
3418
+ durga_ashtami: "Durga Ashtami",
3419
+ maha_navami: "Maha Navami",
3420
+ dussehra: "Dussehra",
3421
+ sharad_purnima: "Sharad Purnima",
3422
+ karva_chauth: "Karva Chauth",
3423
+ dhanteras: "Dhanteras",
3424
+ narak_chaturdashi: "Narak Chaturdashi",
3425
+ diwali: "Diwali",
3426
+ vasant_panchami: "Vasant Panchami",
3427
+ maha_shivaratri: "Maha Shivaratri",
3428
+ holi: "Holi",
3429
+ mahalaya_amavasya: "Mahalaya Amavasya",
3430
+ kartika_purnima: "Kartika Purnima"
3431
+ },
3432
+ misc: {
3433
+ purnima: "Purnima",
3434
+ amavasya: "Amavasya",
3435
+ adhika: "Adhika",
3436
+ ekadashi: "Ekadashi",
3437
+ pradosha: "Pradosha Vrata",
3438
+ sankranti: "Sankranti"
3439
+ }
3197
3440
  };
3198
3441
 
3199
3442
  // src/i18n/sa.ts
@@ -3315,8 +3558,48 @@ var sa = {
3315
3558
  "\u092B\u093E\u0932\u094D\u0917\u0941\u0928"
3316
3559
  ],
3317
3560
  choghadiyaNames: ["\u0909\u0926\u094D\u0935\u0947\u0917", "\u091A\u0930", "\u0932\u093E\u092D", "\u0905\u092E\u0943\u0924", "\u0915\u093E\u0932", "\u0936\u0941\u092D", "\u0930\u094B\u0917"],
3561
+ gowriNames: ["\u0909\u0926\u094D\u092F\u094B\u0917", "\u0905\u092E\u0943\u0924", "\u0930\u094B\u0917", "\u0932\u093E\u092D", "\u0936\u0941\u092D", "\u0915\u093E\u0932", "\u0927\u0928", "\u091A\u0932"],
3318
3562
  grahaNames: ["\u0938\u0942\u0930\u094D\u092F", "\u0936\u0941\u0915\u094D\u0930", "\u092C\u0941\u0927", "\u091A\u0928\u094D\u0926\u094D\u0930", "\u0936\u0928\u093F", "\u0917\u0941\u0930\u0941", "\u092E\u0919\u094D\u0917\u0932"],
3319
- misc: { purnima: "\u092A\u0942\u0930\u094D\u0923\u093F\u092E\u093E", amavasya: "\u0905\u092E\u093E\u0935\u093E\u0938\u094D\u092F\u093E", adhika: "\u0905\u0927\u093F\u0915" }
3563
+ specialYogaNames: {
3564
+ amrit_siddhi: "\u0905\u092E\u0943\u0924 \u0938\u093F\u0926\u094D\u0927\u093F \u092F\u094B\u0917",
3565
+ sarvartha_siddhi: "\u0938\u0930\u094D\u0935\u093E\u0930\u094D\u0925 \u0938\u093F\u0926\u094D\u0927\u093F \u092F\u094B\u0917",
3566
+ ravi_pushya: "\u0930\u0935\u093F \u092A\u0941\u0937\u094D\u092F \u092F\u094B\u0917",
3567
+ guru_pushya: "\u0917\u0941\u0930\u0941 \u092A\u0941\u0937\u094D\u092F \u092F\u094B\u0917"
3568
+ },
3569
+ festivalNames: {
3570
+ ugadi: "\u092F\u0941\u0917\u093E\u0926\u093F",
3571
+ rama_navami: "\u0930\u093E\u092E \u0928\u0935\u092E\u0940",
3572
+ hanuman_jayanti: "\u0939\u0928\u0941\u092E\u093E\u0928 \u091C\u092F\u0928\u094D\u0924\u0940",
3573
+ akshaya_tritiya: "\u0905\u0915\u094D\u0937\u092F \u0924\u0943\u0924\u0940\u092F\u093E",
3574
+ guru_purnima: "\u0917\u0941\u0930\u0941 \u092A\u0942\u0930\u094D\u0923\u093F\u092E\u093E",
3575
+ nag_panchami: "\u0928\u093E\u0917 \u092A\u091E\u094D\u091A\u092E\u0940",
3576
+ raksha_bandhan: "\u0930\u0915\u094D\u0937\u093E \u092C\u0928\u094D\u0927\u0928",
3577
+ krishna_janmashtami: "\u0915\u0943\u0937\u094D\u0923 \u091C\u0928\u094D\u092E\u093E\u0937\u094D\u091F\u092E\u0940",
3578
+ ganesh_chaturthi: "\u0917\u0923\u0947\u0936 \u091A\u0924\u0941\u0930\u094D\u0925\u0940",
3579
+ anant_chaturdashi: "\u0905\u0928\u0928\u094D\u0924 \u091A\u0924\u0941\u0930\u094D\u0926\u0936\u0940",
3580
+ navaratri: "\u0936\u0930\u0926 \u0928\u0935\u0930\u093E\u0924\u094D\u0930\u093F",
3581
+ durga_ashtami: "\u0926\u0941\u0930\u094D\u0917\u093E \u0905\u0937\u094D\u091F\u092E\u0940",
3582
+ maha_navami: "\u092E\u0939\u093E \u0928\u0935\u092E\u0940",
3583
+ dussehra: "\u0926\u0936\u0939\u0930\u093E",
3584
+ sharad_purnima: "\u0936\u0930\u0926 \u092A\u0942\u0930\u094D\u0923\u093F\u092E\u093E",
3585
+ karva_chauth: "\u0915\u0930\u0935\u093E \u091A\u094C\u0925",
3586
+ dhanteras: "\u0927\u0928\u0924\u0947\u0930\u0938",
3587
+ narak_chaturdashi: "\u0928\u0930\u0915 \u091A\u0924\u0941\u0930\u094D\u0926\u0936\u0940",
3588
+ diwali: "\u0926\u0940\u092A\u093E\u0935\u0932\u0940",
3589
+ vasant_panchami: "\u0935\u0938\u0928\u094D\u0924 \u092A\u091E\u094D\u091A\u092E\u0940",
3590
+ maha_shivaratri: "\u092E\u0939\u093E \u0936\u093F\u0935\u0930\u093E\u0924\u094D\u0930\u093F",
3591
+ holi: "\u0939\u094B\u0932\u0940",
3592
+ mahalaya_amavasya: "\u092E\u0939\u093E\u0932\u092F \u0905\u092E\u093E\u0935\u093E\u0938\u094D\u092F\u093E",
3593
+ kartika_purnima: "\u0915\u093E\u0930\u094D\u0924\u093F\u0915 \u092A\u0942\u0930\u094D\u0923\u093F\u092E\u093E"
3594
+ },
3595
+ misc: {
3596
+ purnima: "\u092A\u0942\u0930\u094D\u0923\u093F\u092E\u093E",
3597
+ amavasya: "\u0905\u092E\u093E\u0935\u093E\u0938\u094D\u092F\u093E",
3598
+ adhika: "\u0905\u0927\u093F\u0915",
3599
+ ekadashi: "\u090F\u0915\u093E\u0926\u0936\u0940",
3600
+ pradosha: "\u092A\u094D\u0930\u0926\u094B\u0937 \u0935\u094D\u0930\u0924",
3601
+ sankranti: "\u0938\u0919\u094D\u0915\u094D\u0930\u093E\u0928\u094D\u0924\u093F"
3602
+ }
3320
3603
  };
3321
3604
 
3322
3605
  // src/i18n/hi.ts
@@ -3438,6 +3721,22 @@ function getInstantPanchang(date, location, options) {
3438
3721
  maxIter
3439
3722
  );
3440
3723
  }
3724
+ const t = getTranslations(lang);
3725
+ const specialYogas = computeSpecialYogas(
3726
+ vara.index,
3727
+ tithi.index,
3728
+ Math.floor(siderealMoon / NAKSHATRA_SPAN),
3729
+ (type) => t.specialYogaNames[type] ?? type
3730
+ );
3731
+ const festivals = computeFestivals(
3732
+ tithi.index,
3733
+ Math.floor(siderealMoon / NAKSHATRA_SPAN),
3734
+ chandramasa.index,
3735
+ chandramasa.isAdhika,
3736
+ vara.index,
3737
+ siderealSun,
3738
+ (key) => t.festivalNames[key] ?? t.misc[key] ?? key
3739
+ );
3441
3740
  return {
3442
3741
  timestamp: date,
3443
3742
  location,
@@ -3453,7 +3752,9 @@ function getInstantPanchang(date, location, options) {
3453
3752
  samvat,
3454
3753
  chandraRashi,
3455
3754
  suryaNakshatra,
3456
- panchaka: computePanchaka(siderealMoon)
3755
+ panchaka: computePanchaka(siderealMoon),
3756
+ specialYogas,
3757
+ festivals
3457
3758
  };
3458
3759
  }
3459
3760
  function getDailyPanchang(date, location, options) {
@@ -3524,9 +3825,33 @@ function getDailyPanchang(date, location, options) {
3524
3825
  vara.index,
3525
3826
  (idx) => getTranslations(lang).grahaNames[idx]
3526
3827
  );
3828
+ const gowriPanchangam = computeGowriPanchangam(
3829
+ sunriseUtc,
3830
+ sunsetUtc,
3831
+ nextSunriseUtc,
3832
+ vara.index,
3833
+ (idx) => getTranslations(lang).gowriNames[idx]
3834
+ );
3527
3835
  const moonriseUtc = getMoonrise(localMidnightUtc, location);
3528
3836
  const moonsetUtc = getMoonset(localMidnightUtc, location);
3529
3837
  const panchaka = computePanchaka(siderealMoonAtSunrise);
3838
+ const t = getTranslations(lang);
3839
+ const specialYogas = computeSpecialYogas(
3840
+ vara.index,
3841
+ tithiAtSunrise.index,
3842
+ Math.floor(siderealMoonAtSunrise / NAKSHATRA_SPAN),
3843
+ (type) => t.specialYogaNames[type] ?? type
3844
+ );
3845
+ const durMuhurtaUtc = computeDurMuhurta(sunriseUtc, sunsetUtc, vara.index);
3846
+ const festivals = computeFestivals(
3847
+ tithiAtSunrise.index,
3848
+ Math.floor(siderealMoonAtSunrise / NAKSHATRA_SPAN),
3849
+ chandramasa.index,
3850
+ chandramasa.isAdhika,
3851
+ vara.index,
3852
+ siderealSunAtSunrise,
3853
+ (key) => t.festivalNames[key] ?? t.misc[key] ?? key
3854
+ );
3530
3855
  let tithis;
3531
3856
  let nakshatras;
3532
3857
  let yogas;
@@ -3606,9 +3931,9 @@ function getDailyPanchang(date, location, options) {
3606
3931
  });
3607
3932
  const dayDurationMs = sunsetUtc.getTime() - sunriseUtc.getTime();
3608
3933
  const nightDurationMs = nextSunriseUtc.getTime() - sunsetUtc.getTime();
3609
- for (const t of tithis) {
3610
- t.endTime = toLocalOrNull(t.endTime);
3611
- t.startTime = toLocalOrNull(t.startTime);
3934
+ for (const t2 of tithis) {
3935
+ t2.endTime = toLocalOrNull(t2.endTime);
3936
+ t2.startTime = toLocalOrNull(t2.startTime);
3612
3937
  }
3613
3938
  for (const n of nakshatras) {
3614
3939
  n.endTime = toLocalOrNull(n.endTime);
@@ -3659,7 +3984,14 @@ function getDailyPanchang(date, location, options) {
3659
3984
  },
3660
3985
  moonrise: moonriseUtc ? toLocal(moonriseUtc) : null,
3661
3986
  moonset: moonsetUtc ? toLocal(moonsetUtc) : null,
3662
- panchaka
3987
+ panchaka,
3988
+ specialYogas,
3989
+ durMuhurta: [convertTimePeriod(durMuhurtaUtc[0]), convertTimePeriod(durMuhurtaUtc[1])],
3990
+ festivals,
3991
+ gowriPanchangam: {
3992
+ day: gowriPanchangam.day.map((s) => ({ ...s, ...convertTimePeriod(s) })),
3993
+ night: gowriPanchangam.night.map((s) => ({ ...s, ...convertTimePeriod(s) }))
3994
+ }
3663
3995
  };
3664
3996
  }
3665
3997
  /*! Bundled license information:
@@ -3703,6 +4035,7 @@ astronomy-engine/esm/astronomy.js:
3703
4035
  exports.PanchangError = PanchangError;
3704
4036
  exports.computeAbhijitMuhurta = computeAbhijitMuhurta;
3705
4037
  exports.computeBrahmaMuhurta = computeBrahmaMuhurta;
4038
+ exports.computeGowriPanchangam = computeGowriPanchangam;
3706
4039
  exports.computeGulikaKalam = computeGulikaKalam;
3707
4040
  exports.computeRahuKalam = computeRahuKalam;
3708
4041
  exports.computeYamaganda = computeYamaganda;
package/dist/index.d.cts CHANGED
@@ -95,6 +95,18 @@ interface ChoghadiyaInfo {
95
95
  /** 8 equal slots from sunset to next sunrise */
96
96
  night: ChoghadiyaSlot[];
97
97
  }
98
+ interface GowriSlot extends TimePeriod {
99
+ /** 0–7: index within the 8-name Gowri cycle */
100
+ index: number;
101
+ name: string;
102
+ quality: ChoghadiyaQuality;
103
+ }
104
+ interface GowriInfo {
105
+ /** 8 equal slots from sunrise to sunset */
106
+ day: GowriSlot[];
107
+ /** 8 equal slots from sunset to next sunrise */
108
+ night: GowriSlot[];
109
+ }
98
110
  interface HoraSlot extends TimePeriod {
99
111
  /** 0–6 in Chaldean order: Sun, Venus, Mercury, Moon, Saturn, Jupiter, Mars */
100
112
  planetIndex: number;
@@ -112,6 +124,15 @@ interface SamvatInfo {
112
124
  /** Shaka Samvat year (same new-year point, offset 135 years behind VS) */
113
125
  shakaSamvat: number;
114
126
  }
127
+ interface SpecialYogaInfo {
128
+ name: string;
129
+ type: 'amrit_siddhi' | 'sarvartha_siddhi' | 'ravi_pushya' | 'guru_pushya';
130
+ }
131
+ interface FestivalInfo {
132
+ name: string;
133
+ type: 'major' | 'minor' | 'ekadashi' | 'pradosha' | 'sankranti';
134
+ description?: string;
135
+ }
115
136
 
116
137
  interface MasaInfo {
117
138
  index: number;
@@ -150,6 +171,10 @@ interface DailyPanchangResult {
150
171
  moonrise: Date | null;
151
172
  moonset: Date | null;
152
173
  panchaka: boolean;
174
+ specialYogas: SpecialYogaInfo[];
175
+ durMuhurta: [TimePeriod, TimePeriod];
176
+ festivals: FestivalInfo[];
177
+ gowriPanchangam: GowriInfo;
153
178
  _debug?: {
154
179
  totalMs: number;
155
180
  sunriseMs: number;
@@ -174,6 +199,8 @@ interface InstantPanchangResult {
174
199
  /** Sun's current Nakshatra (changes every ~13–14 days) */
175
200
  suryaNakshatra: RashiInfo;
176
201
  panchaka: boolean;
202
+ specialYogas: SpecialYogaInfo[];
203
+ festivals: FestivalInfo[];
177
204
  }
178
205
 
179
206
  /**
@@ -374,11 +401,10 @@ declare function computeYamaganda(sunrise: Date, sunset: Date, varaIndex: number
374
401
  */
375
402
  declare function computeAbhijitMuhurta(sunrise: Date, sunset: Date): TimePeriod;
376
403
  /**
377
- * Brahma Muhurta: the auspicious 96-minute window ending 48 minutes before sunrise.
404
+ * Brahma Muhurta: the two muhurtas immediately before sunrise.
378
405
  *
379
- * Daytime is divided into 30 equal muhurtas (each ≈ 48 min for a 12-hour day).
380
- * Brahma Muhurta spans the 29th and 30th muhurtas of the *preceding* night,
381
- * i.e. the two muhurtas immediately before sunrise.
406
+ * Muhurta length is proportional to the day: dayDuration / 30.
407
+ * For a typical 12-hour day this equals ~24 min, making the window ~48–24 min before sunrise.
382
408
  *
383
409
  * Start: sunrise − 2 × muhurtaDuration
384
410
  * End: sunrise − 1 × muhurtaDuration
@@ -388,10 +414,26 @@ declare function computeAbhijitMuhurta(sunrise: Date, sunset: Date): TimePeriod;
388
414
  */
389
415
  declare function computeBrahmaMuhurta(sunrise: Date, sunset: Date): TimePeriod;
390
416
 
417
+ /**
418
+ * Compute the 16 Gowri Panchangam (Gowri Nalla Neram) slots for a day
419
+ * (8 daytime + 8 nighttime).
420
+ *
421
+ * Each half is divided into 8 equal periods named from an 8-name cycle
422
+ * (Udyog → Amrit → Roga → Laabh → Shubh → Kaal → Dhan → Chal).
423
+ * The starting name depends on the weekday (vara).
424
+ *
425
+ * @param sunrise UTC sunrise Date.
426
+ * @param sunset UTC sunset Date.
427
+ * @param nextSunrise UTC next-day sunrise Date.
428
+ * @param varaIndex Weekday index: 0 = Sunday, 6 = Saturday.
429
+ * @param nameFn Callback returning translated Gowri slot name for index 0–7.
430
+ */
431
+ declare function computeGowriPanchangam(sunrise: Date, sunset: Date, nextSunrise: Date, varaIndex: number, nameFn: (index: number) => string): GowriInfo;
432
+
391
433
  type PanchangErrorCode = 'INVALID_LATITUDE' | 'INVALID_LONGITUDE' | 'INVALID_ELEVATION' | 'INVALID_DATE' | 'INVALID_TIMEZONE' | 'INVALID_AYANAMSA' | 'TIMEZONE_RESOLUTION_FAILED' | 'NO_SUNRISE' | 'NO_SUNSET' | 'SEARCH_DIVERGED';
392
434
  declare class PanchangError extends Error {
393
435
  readonly code: PanchangErrorCode;
394
436
  constructor(message: string, code: PanchangErrorCode);
395
437
  }
396
438
 
397
- export { type AyanamsaType, type ChandraMasaInfo, type ChoghadiyaInfo, type ChoghadiyaQuality, type ChoghadiyaSlot, type DailyKaranaInfo, type DailyNakshatraInfo, type DailyPanchangResult, type DailyTithiInfo, type DailyYogaInfo, type GeoLocation, type HoraInfo, type HoraSlot, type InstantPanchangOptions, type InstantPanchangResult, type KaranaInfo, type Language, type MasaInfo, type NakshatraInfo, PanchangError, type PanchangErrorCode, type PanchangOptions, type Precision, type RashiInfo, type SamvatInfo, type TimePeriod, type TithiInfo, type VaraInfo, type YogaInfo, computeAbhijitMuhurta, computeBrahmaMuhurta, computeGulikaKalam, computeRahuKalam, computeYamaganda, computeAyanamsa as getAyanamsa, getDailyPanchang, getInstantPanchang, getMoonrise, getMoonset, getSiderealMoonLongitude, getSiderealSunLongitude, computeSunrise as getSunrise, computeSunset as getSunset };
439
+ export { type AyanamsaType, type ChandraMasaInfo, type ChoghadiyaInfo, type ChoghadiyaQuality, type ChoghadiyaSlot, type DailyKaranaInfo, type DailyNakshatraInfo, type DailyPanchangResult, type DailyTithiInfo, type DailyYogaInfo, type FestivalInfo, type GeoLocation, type GowriInfo, type GowriSlot, type HoraInfo, type HoraSlot, type InstantPanchangOptions, type InstantPanchangResult, type KaranaInfo, type Language, type MasaInfo, type NakshatraInfo, PanchangError, type PanchangErrorCode, type PanchangOptions, type Precision, type RashiInfo, type SamvatInfo, type SpecialYogaInfo, type TimePeriod, type TithiInfo, type VaraInfo, type YogaInfo, computeAbhijitMuhurta, computeBrahmaMuhurta, computeGowriPanchangam, computeGulikaKalam, computeRahuKalam, computeYamaganda, computeAyanamsa as getAyanamsa, getDailyPanchang, getInstantPanchang, getMoonrise, getMoonset, getSiderealMoonLongitude, getSiderealSunLongitude, computeSunrise as getSunrise, computeSunset as getSunset };
package/dist/index.d.ts CHANGED
@@ -95,6 +95,18 @@ interface ChoghadiyaInfo {
95
95
  /** 8 equal slots from sunset to next sunrise */
96
96
  night: ChoghadiyaSlot[];
97
97
  }
98
+ interface GowriSlot extends TimePeriod {
99
+ /** 0–7: index within the 8-name Gowri cycle */
100
+ index: number;
101
+ name: string;
102
+ quality: ChoghadiyaQuality;
103
+ }
104
+ interface GowriInfo {
105
+ /** 8 equal slots from sunrise to sunset */
106
+ day: GowriSlot[];
107
+ /** 8 equal slots from sunset to next sunrise */
108
+ night: GowriSlot[];
109
+ }
98
110
  interface HoraSlot extends TimePeriod {
99
111
  /** 0–6 in Chaldean order: Sun, Venus, Mercury, Moon, Saturn, Jupiter, Mars */
100
112
  planetIndex: number;
@@ -112,6 +124,15 @@ interface SamvatInfo {
112
124
  /** Shaka Samvat year (same new-year point, offset 135 years behind VS) */
113
125
  shakaSamvat: number;
114
126
  }
127
+ interface SpecialYogaInfo {
128
+ name: string;
129
+ type: 'amrit_siddhi' | 'sarvartha_siddhi' | 'ravi_pushya' | 'guru_pushya';
130
+ }
131
+ interface FestivalInfo {
132
+ name: string;
133
+ type: 'major' | 'minor' | 'ekadashi' | 'pradosha' | 'sankranti';
134
+ description?: string;
135
+ }
115
136
 
116
137
  interface MasaInfo {
117
138
  index: number;
@@ -150,6 +171,10 @@ interface DailyPanchangResult {
150
171
  moonrise: Date | null;
151
172
  moonset: Date | null;
152
173
  panchaka: boolean;
174
+ specialYogas: SpecialYogaInfo[];
175
+ durMuhurta: [TimePeriod, TimePeriod];
176
+ festivals: FestivalInfo[];
177
+ gowriPanchangam: GowriInfo;
153
178
  _debug?: {
154
179
  totalMs: number;
155
180
  sunriseMs: number;
@@ -174,6 +199,8 @@ interface InstantPanchangResult {
174
199
  /** Sun's current Nakshatra (changes every ~13–14 days) */
175
200
  suryaNakshatra: RashiInfo;
176
201
  panchaka: boolean;
202
+ specialYogas: SpecialYogaInfo[];
203
+ festivals: FestivalInfo[];
177
204
  }
178
205
 
179
206
  /**
@@ -374,11 +401,10 @@ declare function computeYamaganda(sunrise: Date, sunset: Date, varaIndex: number
374
401
  */
375
402
  declare function computeAbhijitMuhurta(sunrise: Date, sunset: Date): TimePeriod;
376
403
  /**
377
- * Brahma Muhurta: the auspicious 96-minute window ending 48 minutes before sunrise.
404
+ * Brahma Muhurta: the two muhurtas immediately before sunrise.
378
405
  *
379
- * Daytime is divided into 30 equal muhurtas (each ≈ 48 min for a 12-hour day).
380
- * Brahma Muhurta spans the 29th and 30th muhurtas of the *preceding* night,
381
- * i.e. the two muhurtas immediately before sunrise.
406
+ * Muhurta length is proportional to the day: dayDuration / 30.
407
+ * For a typical 12-hour day this equals ~24 min, making the window ~48–24 min before sunrise.
382
408
  *
383
409
  * Start: sunrise − 2 × muhurtaDuration
384
410
  * End: sunrise − 1 × muhurtaDuration
@@ -388,10 +414,26 @@ declare function computeAbhijitMuhurta(sunrise: Date, sunset: Date): TimePeriod;
388
414
  */
389
415
  declare function computeBrahmaMuhurta(sunrise: Date, sunset: Date): TimePeriod;
390
416
 
417
+ /**
418
+ * Compute the 16 Gowri Panchangam (Gowri Nalla Neram) slots for a day
419
+ * (8 daytime + 8 nighttime).
420
+ *
421
+ * Each half is divided into 8 equal periods named from an 8-name cycle
422
+ * (Udyog → Amrit → Roga → Laabh → Shubh → Kaal → Dhan → Chal).
423
+ * The starting name depends on the weekday (vara).
424
+ *
425
+ * @param sunrise UTC sunrise Date.
426
+ * @param sunset UTC sunset Date.
427
+ * @param nextSunrise UTC next-day sunrise Date.
428
+ * @param varaIndex Weekday index: 0 = Sunday, 6 = Saturday.
429
+ * @param nameFn Callback returning translated Gowri slot name for index 0–7.
430
+ */
431
+ declare function computeGowriPanchangam(sunrise: Date, sunset: Date, nextSunrise: Date, varaIndex: number, nameFn: (index: number) => string): GowriInfo;
432
+
391
433
  type PanchangErrorCode = 'INVALID_LATITUDE' | 'INVALID_LONGITUDE' | 'INVALID_ELEVATION' | 'INVALID_DATE' | 'INVALID_TIMEZONE' | 'INVALID_AYANAMSA' | 'TIMEZONE_RESOLUTION_FAILED' | 'NO_SUNRISE' | 'NO_SUNSET' | 'SEARCH_DIVERGED';
392
434
  declare class PanchangError extends Error {
393
435
  readonly code: PanchangErrorCode;
394
436
  constructor(message: string, code: PanchangErrorCode);
395
437
  }
396
438
 
397
- export { type AyanamsaType, type ChandraMasaInfo, type ChoghadiyaInfo, type ChoghadiyaQuality, type ChoghadiyaSlot, type DailyKaranaInfo, type DailyNakshatraInfo, type DailyPanchangResult, type DailyTithiInfo, type DailyYogaInfo, type GeoLocation, type HoraInfo, type HoraSlot, type InstantPanchangOptions, type InstantPanchangResult, type KaranaInfo, type Language, type MasaInfo, type NakshatraInfo, PanchangError, type PanchangErrorCode, type PanchangOptions, type Precision, type RashiInfo, type SamvatInfo, type TimePeriod, type TithiInfo, type VaraInfo, type YogaInfo, computeAbhijitMuhurta, computeBrahmaMuhurta, computeGulikaKalam, computeRahuKalam, computeYamaganda, computeAyanamsa as getAyanamsa, getDailyPanchang, getInstantPanchang, getMoonrise, getMoonset, getSiderealMoonLongitude, getSiderealSunLongitude, computeSunrise as getSunrise, computeSunset as getSunset };
439
+ export { type AyanamsaType, type ChandraMasaInfo, type ChoghadiyaInfo, type ChoghadiyaQuality, type ChoghadiyaSlot, type DailyKaranaInfo, type DailyNakshatraInfo, type DailyPanchangResult, type DailyTithiInfo, type DailyYogaInfo, type FestivalInfo, type GeoLocation, type GowriInfo, type GowriSlot, type HoraInfo, type HoraSlot, type InstantPanchangOptions, type InstantPanchangResult, type KaranaInfo, type Language, type MasaInfo, type NakshatraInfo, PanchangError, type PanchangErrorCode, type PanchangOptions, type Precision, type RashiInfo, type SamvatInfo, type SpecialYogaInfo, type TimePeriod, type TithiInfo, type VaraInfo, type YogaInfo, computeAbhijitMuhurta, computeBrahmaMuhurta, computeGowriPanchangam, computeGulikaKalam, computeRahuKalam, computeYamaganda, computeAyanamsa as getAyanamsa, getDailyPanchang, getInstantPanchang, getMoonrise, getMoonset, getSiderealMoonLongitude, getSiderealSunLongitude, computeSunrise as getSunrise, computeSunset as getSunset };
package/dist/index.js CHANGED
@@ -2911,6 +2911,51 @@ function computeBrahmaMuhurta(sunrise, sunset) {
2911
2911
  return { start, end };
2912
2912
  }
2913
2913
 
2914
+ // src/core/gowri.ts
2915
+ var GOWRI_QUALITY = [
2916
+ "neutral",
2917
+ // 0 Udyog
2918
+ "auspicious",
2919
+ // 1 Amrit
2920
+ "inauspicious",
2921
+ // 2 Roga
2922
+ "auspicious",
2923
+ // 3 Laabh
2924
+ "auspicious",
2925
+ // 4 Shubh
2926
+ "inauspicious",
2927
+ // 5 Kaal
2928
+ "auspicious",
2929
+ // 6 Dhan
2930
+ "neutral"
2931
+ // 7 Chal
2932
+ ];
2933
+ var DAY_START_INDEX = [6, 5, 4, 3, 2, 1, 0];
2934
+ var NIGHT_START_INDEX = [2, 1, 0, 7, 6, 5, 4];
2935
+ function buildSlots(reference, durationMs, startIndex, nameFn) {
2936
+ const slotMs = durationMs / 8;
2937
+ const slots = [];
2938
+ for (let i = 0; i < 8; i++) {
2939
+ const idx = (startIndex + i) % 8;
2940
+ slots.push({
2941
+ start: new Date(reference.getTime() + i * slotMs),
2942
+ end: new Date(reference.getTime() + (i + 1) * slotMs),
2943
+ index: idx,
2944
+ name: nameFn(idx),
2945
+ quality: GOWRI_QUALITY[idx]
2946
+ });
2947
+ }
2948
+ return slots;
2949
+ }
2950
+ function computeGowriPanchangam(sunrise, sunset, nextSunrise, varaIndex, nameFn) {
2951
+ const dayMs = sunset.getTime() - sunrise.getTime();
2952
+ const nightMs = nextSunrise.getTime() - sunset.getTime();
2953
+ return {
2954
+ day: buildSlots(sunrise, dayMs, DAY_START_INDEX[varaIndex], nameFn),
2955
+ night: buildSlots(sunset, nightMs, NIGHT_START_INDEX[varaIndex], nameFn)
2956
+ };
2957
+ }
2958
+
2914
2959
  // src/core/masa.ts
2915
2960
  var MASA_NAMES_EN = [
2916
2961
  "Mesha",
@@ -2991,9 +3036,9 @@ var CHOGHADIYA_QUALITY = [
2991
3036
  "inauspicious"
2992
3037
  // 6 Rog (Mars)
2993
3038
  ];
2994
- var DAY_START_INDEX = [0, 3, 6, 2, 5, 1, 4];
2995
- var NIGHT_START_INDEX = [5, 1, 4, 6, 0, 3, 2];
2996
- function buildSlots(reference, durationMs, startIndex, nameFn, count) {
3039
+ var DAY_START_INDEX2 = [0, 3, 6, 2, 5, 1, 4];
3040
+ var NIGHT_START_INDEX2 = [5, 1, 4, 6, 0, 3, 2];
3041
+ function buildSlots2(reference, durationMs, startIndex, nameFn, count) {
2997
3042
  const slotMs = durationMs / count;
2998
3043
  const slots = [];
2999
3044
  for (let i = 0; i < count; i++) {
@@ -3012,8 +3057,8 @@ function computeChoghadiya(sunrise, sunset, nextSunrise, varaIndex, nameFn) {
3012
3057
  const dayMs = sunset.getTime() - sunrise.getTime();
3013
3058
  const nightMs = nextSunrise.getTime() - sunset.getTime();
3014
3059
  return {
3015
- day: buildSlots(sunrise, dayMs, DAY_START_INDEX[varaIndex], nameFn, 8),
3016
- night: buildSlots(sunset, nightMs, NIGHT_START_INDEX[varaIndex], nameFn, 8)
3060
+ day: buildSlots2(sunrise, dayMs, DAY_START_INDEX2[varaIndex], nameFn, 8),
3061
+ night: buildSlots2(sunset, nightMs, NIGHT_START_INDEX2[varaIndex], nameFn, 8)
3017
3062
  };
3018
3063
  }
3019
3064
 
@@ -3049,6 +3094,164 @@ function computePanchaka(siderealMoon) {
3049
3094
  return siderealMoon >= 300;
3050
3095
  }
3051
3096
 
3097
+ // src/core/specialYogas.ts
3098
+ var AMRIT_SIDDHI_TABLE = /* @__PURE__ */ new Map([
3099
+ [0, /* @__PURE__ */ new Set([1, 4, 6, 9, 14])],
3100
+ // Sunday
3101
+ [1, /* @__PURE__ */ new Set([2, 7, 12])],
3102
+ // Monday
3103
+ [2, /* @__PURE__ */ new Set([3, 8, 13])],
3104
+ // Tuesday
3105
+ [3, /* @__PURE__ */ new Set([5, 10, 15])],
3106
+ // Wednesday
3107
+ [4, /* @__PURE__ */ new Set([6, 11])],
3108
+ // Thursday
3109
+ [5, /* @__PURE__ */ new Set([2, 7, 12])],
3110
+ // Friday
3111
+ [6, /* @__PURE__ */ new Set([3, 8, 13])]
3112
+ // Saturday
3113
+ ]);
3114
+ var SARVARTHA_SIDDHI_TABLE = /* @__PURE__ */ new Map([
3115
+ [0, /* @__PURE__ */ new Set([7, 11, 12, 20, 21, 25])],
3116
+ // Sunday: Pushya, UPhalguni, Hasta, UAshadha, Shravana, UBhadrapada
3117
+ [1, /* @__PURE__ */ new Set([3, 4, 7, 12, 16, 21])],
3118
+ // Monday: Rohini, Mrigashira, Pushya, Hasta, Anuradha, Shravana
3119
+ [2, /* @__PURE__ */ new Set([0, 2, 11, 20, 25])],
3120
+ // Tuesday: Ashwini, Krittika, UPhalguni, UAshadha, UBhadrapada
3121
+ [3, /* @__PURE__ */ new Set([1, 3, 4, 12, 16])],
3122
+ // Wednesday: Bharani, Rohini, Mrigashira, Hasta, Anuradha
3123
+ [4, /* @__PURE__ */ new Set([0, 6, 7, 14, 16, 26])],
3124
+ // Thursday: Ashwini, Punarvasu, Pushya, Swati, Anuradha, Revati
3125
+ [5, /* @__PURE__ */ new Set([0, 1, 6, 13, 21, 26])],
3126
+ // Friday: Ashwini, Bharani, Punarvasu, Chitra, Shravana, Revati
3127
+ [6, /* @__PURE__ */ new Set([3, 14, 21, 26])]
3128
+ // Saturday: Rohini, Swati, Shravana, Revati
3129
+ ]);
3130
+ function computeSpecialYogas(varaIndex, tithiIndex, nakshatraIndex, nameResolver) {
3131
+ const results = [];
3132
+ const tithiNumber = tithiIndex % 15 + 1;
3133
+ if (AMRIT_SIDDHI_TABLE.get(varaIndex)?.has(tithiNumber)) {
3134
+ results.push({ name: nameResolver("amrit_siddhi"), type: "amrit_siddhi" });
3135
+ }
3136
+ if (SARVARTHA_SIDDHI_TABLE.get(varaIndex)?.has(nakshatraIndex)) {
3137
+ results.push({ name: nameResolver("sarvartha_siddhi"), type: "sarvartha_siddhi" });
3138
+ }
3139
+ if (varaIndex === 0 && nakshatraIndex === 7) {
3140
+ results.push({ name: nameResolver("ravi_pushya"), type: "ravi_pushya" });
3141
+ }
3142
+ if (varaIndex === 4 && nakshatraIndex === 7) {
3143
+ results.push({ name: nameResolver("guru_pushya"), type: "guru_pushya" });
3144
+ }
3145
+ return results;
3146
+ }
3147
+
3148
+ // src/core/durMuhurta.ts
3149
+ var DUR_MUHURTA_INDICES = [
3150
+ [7, 13],
3151
+ // Sunday
3152
+ [3, 10],
3153
+ // Monday
3154
+ [5, 14],
3155
+ // Tuesday
3156
+ [2, 11],
3157
+ // Wednesday
3158
+ [6, 12],
3159
+ // Thursday
3160
+ [4, 9],
3161
+ // Friday
3162
+ [1, 8]
3163
+ // Saturday
3164
+ ];
3165
+ function computeDurMuhurta(sunrise, sunset, varaIndex) {
3166
+ const dayMs = sunset.getTime() - sunrise.getTime();
3167
+ const muhurtaMs = dayMs / 15;
3168
+ const sunriseMs = sunrise.getTime();
3169
+ const [idx1, idx2] = DUR_MUHURTA_INDICES[varaIndex];
3170
+ return [
3171
+ {
3172
+ start: new Date(sunriseMs + idx1 * muhurtaMs),
3173
+ end: new Date(sunriseMs + (idx1 + 1) * muhurtaMs)
3174
+ },
3175
+ {
3176
+ start: new Date(sunriseMs + idx2 * muhurtaMs),
3177
+ end: new Date(sunriseMs + (idx2 + 1) * muhurtaMs)
3178
+ }
3179
+ ];
3180
+ }
3181
+
3182
+ // src/core/festivals.ts
3183
+ var FESTIVAL_REGISTRY = [
3184
+ // Chaitra (0)
3185
+ { key: "ugadi", masa: 0, tithi: 0, type: "major" },
3186
+ { key: "rama_navami", masa: 0, tithi: 8, type: "major" },
3187
+ { key: "hanuman_jayanti", masa: 0, tithi: 14, type: "major" },
3188
+ // Vaishakha (1)
3189
+ { key: "akshaya_tritiya", masa: 1, tithi: 2, type: "major" },
3190
+ // Ashadha (3)
3191
+ { key: "guru_purnima", masa: 3, tithi: 14, type: "major" },
3192
+ // Shravana (4)
3193
+ { key: "nag_panchami", masa: 4, tithi: 4, type: "minor" },
3194
+ { key: "raksha_bandhan", masa: 4, tithi: 14, type: "major" },
3195
+ { key: "krishna_janmashtami", masa: 4, tithi: 22, type: "major" },
3196
+ // Bhadrapada (5)
3197
+ { key: "ganesh_chaturthi", masa: 5, tithi: 3, type: "major" },
3198
+ { key: "anant_chaturdashi", masa: 5, tithi: 13, type: "major" },
3199
+ // Ashwin (6)
3200
+ { key: "navaratri", masa: 6, tithi: 0, type: "major" },
3201
+ { key: "durga_ashtami", masa: 6, tithi: 7, type: "major" },
3202
+ { key: "maha_navami", masa: 6, tithi: 8, type: "major" },
3203
+ { key: "dussehra", masa: 6, tithi: 9, type: "major" },
3204
+ { key: "sharad_purnima", masa: 6, tithi: 14, type: "major" },
3205
+ // Kartika (7)
3206
+ { key: "karva_chauth", masa: 7, tithi: 18, type: "major" },
3207
+ { key: "dhanteras", masa: 7, tithi: 27, type: "major" },
3208
+ { key: "narak_chaturdashi", masa: 7, tithi: 28, type: "major" },
3209
+ { key: "diwali", masa: 7, tithi: 29, type: "major" },
3210
+ { key: "kartika_purnima", masa: 7, tithi: 14, type: "minor" },
3211
+ // Magha (10)
3212
+ { key: "vasant_panchami", masa: 10, tithi: 4, type: "major" },
3213
+ { key: "maha_shivaratri", masa: 10, tithi: 28, type: "major" },
3214
+ // Phalguna (11)
3215
+ { key: "holi", masa: 11, tithi: 14, type: "major" },
3216
+ // Bhadrapada (5) — end of Pitru Paksha
3217
+ { key: "mahalaya_amavasya", masa: 5, tithi: 29, type: "major" }
3218
+ ];
3219
+ function computeFestivals(tithiIndex, _nakshatraIndex, chandraMasaIndex, isAdhika, _varaIndex, siderealSun, nameResolver) {
3220
+ const results = [];
3221
+ if (!isAdhika) {
3222
+ for (const rule of FESTIVAL_REGISTRY) {
3223
+ if (rule.masa === chandraMasaIndex && rule.tithi === tithiIndex) {
3224
+ results.push({
3225
+ name: nameResolver(rule.key),
3226
+ type: rule.type
3227
+ });
3228
+ }
3229
+ }
3230
+ }
3231
+ if (tithiIndex === 10 || tithiIndex === 25) {
3232
+ results.push({
3233
+ name: nameResolver("ekadashi"),
3234
+ type: "ekadashi"
3235
+ });
3236
+ }
3237
+ if (tithiIndex === 27) {
3238
+ results.push({
3239
+ name: nameResolver("pradosha"),
3240
+ type: "pradosha"
3241
+ });
3242
+ }
3243
+ const degInRashi = siderealSun % 30;
3244
+ if (degInRashi < 1) {
3245
+ const rashiIndex = Math.floor(siderealSun / 30) % 12;
3246
+ results.push({
3247
+ name: nameResolver("sankranti"),
3248
+ type: "sankranti",
3249
+ description: `Rashi ${rashiIndex}`
3250
+ });
3251
+ }
3252
+ return results;
3253
+ }
3254
+
3052
3255
  // src/astronomy/moonrise.ts
3053
3256
  function getMoonrise(searchFromUtc, location, limitDays = 2) {
3054
3257
  const observer = new Observer(
@@ -3190,8 +3393,48 @@ var en = {
3190
3393
  "Phalguna"
3191
3394
  ],
3192
3395
  choghadiyaNames: ["Udveg", "Char", "Labh", "Amrit", "Kaal", "Shubh", "Rog"],
3396
+ gowriNames: ["Udyog", "Amrit", "Roga", "Laabh", "Shubh", "Kaal", "Dhan", "Chal"],
3193
3397
  grahaNames: ["Sun", "Venus", "Mercury", "Moon", "Saturn", "Jupiter", "Mars"],
3194
- misc: { purnima: "Purnima", amavasya: "Amavasya", adhika: "Adhika" }
3398
+ specialYogaNames: {
3399
+ amrit_siddhi: "Amrit Siddhi Yoga",
3400
+ sarvartha_siddhi: "Sarvartha Siddhi Yoga",
3401
+ ravi_pushya: "Ravi Pushya Yoga",
3402
+ guru_pushya: "Guru Pushya Yoga"
3403
+ },
3404
+ festivalNames: {
3405
+ ugadi: "Ugadi",
3406
+ rama_navami: "Rama Navami",
3407
+ hanuman_jayanti: "Hanuman Jayanti",
3408
+ akshaya_tritiya: "Akshaya Tritiya",
3409
+ guru_purnima: "Guru Purnima",
3410
+ nag_panchami: "Nag Panchami",
3411
+ raksha_bandhan: "Raksha Bandhan",
3412
+ krishna_janmashtami: "Krishna Janmashtami",
3413
+ ganesh_chaturthi: "Ganesh Chaturthi",
3414
+ anant_chaturdashi: "Anant Chaturdashi",
3415
+ navaratri: "Sharad Navaratri",
3416
+ durga_ashtami: "Durga Ashtami",
3417
+ maha_navami: "Maha Navami",
3418
+ dussehra: "Dussehra",
3419
+ sharad_purnima: "Sharad Purnima",
3420
+ karva_chauth: "Karva Chauth",
3421
+ dhanteras: "Dhanteras",
3422
+ narak_chaturdashi: "Narak Chaturdashi",
3423
+ diwali: "Diwali",
3424
+ vasant_panchami: "Vasant Panchami",
3425
+ maha_shivaratri: "Maha Shivaratri",
3426
+ holi: "Holi",
3427
+ mahalaya_amavasya: "Mahalaya Amavasya",
3428
+ kartika_purnima: "Kartika Purnima"
3429
+ },
3430
+ misc: {
3431
+ purnima: "Purnima",
3432
+ amavasya: "Amavasya",
3433
+ adhika: "Adhika",
3434
+ ekadashi: "Ekadashi",
3435
+ pradosha: "Pradosha Vrata",
3436
+ sankranti: "Sankranti"
3437
+ }
3195
3438
  };
3196
3439
 
3197
3440
  // src/i18n/sa.ts
@@ -3313,8 +3556,48 @@ var sa = {
3313
3556
  "\u092B\u093E\u0932\u094D\u0917\u0941\u0928"
3314
3557
  ],
3315
3558
  choghadiyaNames: ["\u0909\u0926\u094D\u0935\u0947\u0917", "\u091A\u0930", "\u0932\u093E\u092D", "\u0905\u092E\u0943\u0924", "\u0915\u093E\u0932", "\u0936\u0941\u092D", "\u0930\u094B\u0917"],
3559
+ gowriNames: ["\u0909\u0926\u094D\u092F\u094B\u0917", "\u0905\u092E\u0943\u0924", "\u0930\u094B\u0917", "\u0932\u093E\u092D", "\u0936\u0941\u092D", "\u0915\u093E\u0932", "\u0927\u0928", "\u091A\u0932"],
3316
3560
  grahaNames: ["\u0938\u0942\u0930\u094D\u092F", "\u0936\u0941\u0915\u094D\u0930", "\u092C\u0941\u0927", "\u091A\u0928\u094D\u0926\u094D\u0930", "\u0936\u0928\u093F", "\u0917\u0941\u0930\u0941", "\u092E\u0919\u094D\u0917\u0932"],
3317
- misc: { purnima: "\u092A\u0942\u0930\u094D\u0923\u093F\u092E\u093E", amavasya: "\u0905\u092E\u093E\u0935\u093E\u0938\u094D\u092F\u093E", adhika: "\u0905\u0927\u093F\u0915" }
3561
+ specialYogaNames: {
3562
+ amrit_siddhi: "\u0905\u092E\u0943\u0924 \u0938\u093F\u0926\u094D\u0927\u093F \u092F\u094B\u0917",
3563
+ sarvartha_siddhi: "\u0938\u0930\u094D\u0935\u093E\u0930\u094D\u0925 \u0938\u093F\u0926\u094D\u0927\u093F \u092F\u094B\u0917",
3564
+ ravi_pushya: "\u0930\u0935\u093F \u092A\u0941\u0937\u094D\u092F \u092F\u094B\u0917",
3565
+ guru_pushya: "\u0917\u0941\u0930\u0941 \u092A\u0941\u0937\u094D\u092F \u092F\u094B\u0917"
3566
+ },
3567
+ festivalNames: {
3568
+ ugadi: "\u092F\u0941\u0917\u093E\u0926\u093F",
3569
+ rama_navami: "\u0930\u093E\u092E \u0928\u0935\u092E\u0940",
3570
+ hanuman_jayanti: "\u0939\u0928\u0941\u092E\u093E\u0928 \u091C\u092F\u0928\u094D\u0924\u0940",
3571
+ akshaya_tritiya: "\u0905\u0915\u094D\u0937\u092F \u0924\u0943\u0924\u0940\u092F\u093E",
3572
+ guru_purnima: "\u0917\u0941\u0930\u0941 \u092A\u0942\u0930\u094D\u0923\u093F\u092E\u093E",
3573
+ nag_panchami: "\u0928\u093E\u0917 \u092A\u091E\u094D\u091A\u092E\u0940",
3574
+ raksha_bandhan: "\u0930\u0915\u094D\u0937\u093E \u092C\u0928\u094D\u0927\u0928",
3575
+ krishna_janmashtami: "\u0915\u0943\u0937\u094D\u0923 \u091C\u0928\u094D\u092E\u093E\u0937\u094D\u091F\u092E\u0940",
3576
+ ganesh_chaturthi: "\u0917\u0923\u0947\u0936 \u091A\u0924\u0941\u0930\u094D\u0925\u0940",
3577
+ anant_chaturdashi: "\u0905\u0928\u0928\u094D\u0924 \u091A\u0924\u0941\u0930\u094D\u0926\u0936\u0940",
3578
+ navaratri: "\u0936\u0930\u0926 \u0928\u0935\u0930\u093E\u0924\u094D\u0930\u093F",
3579
+ durga_ashtami: "\u0926\u0941\u0930\u094D\u0917\u093E \u0905\u0937\u094D\u091F\u092E\u0940",
3580
+ maha_navami: "\u092E\u0939\u093E \u0928\u0935\u092E\u0940",
3581
+ dussehra: "\u0926\u0936\u0939\u0930\u093E",
3582
+ sharad_purnima: "\u0936\u0930\u0926 \u092A\u0942\u0930\u094D\u0923\u093F\u092E\u093E",
3583
+ karva_chauth: "\u0915\u0930\u0935\u093E \u091A\u094C\u0925",
3584
+ dhanteras: "\u0927\u0928\u0924\u0947\u0930\u0938",
3585
+ narak_chaturdashi: "\u0928\u0930\u0915 \u091A\u0924\u0941\u0930\u094D\u0926\u0936\u0940",
3586
+ diwali: "\u0926\u0940\u092A\u093E\u0935\u0932\u0940",
3587
+ vasant_panchami: "\u0935\u0938\u0928\u094D\u0924 \u092A\u091E\u094D\u091A\u092E\u0940",
3588
+ maha_shivaratri: "\u092E\u0939\u093E \u0936\u093F\u0935\u0930\u093E\u0924\u094D\u0930\u093F",
3589
+ holi: "\u0939\u094B\u0932\u0940",
3590
+ mahalaya_amavasya: "\u092E\u0939\u093E\u0932\u092F \u0905\u092E\u093E\u0935\u093E\u0938\u094D\u092F\u093E",
3591
+ kartika_purnima: "\u0915\u093E\u0930\u094D\u0924\u093F\u0915 \u092A\u0942\u0930\u094D\u0923\u093F\u092E\u093E"
3592
+ },
3593
+ misc: {
3594
+ purnima: "\u092A\u0942\u0930\u094D\u0923\u093F\u092E\u093E",
3595
+ amavasya: "\u0905\u092E\u093E\u0935\u093E\u0938\u094D\u092F\u093E",
3596
+ adhika: "\u0905\u0927\u093F\u0915",
3597
+ ekadashi: "\u090F\u0915\u093E\u0926\u0936\u0940",
3598
+ pradosha: "\u092A\u094D\u0930\u0926\u094B\u0937 \u0935\u094D\u0930\u0924",
3599
+ sankranti: "\u0938\u0919\u094D\u0915\u094D\u0930\u093E\u0928\u094D\u0924\u093F"
3600
+ }
3318
3601
  };
3319
3602
 
3320
3603
  // src/i18n/hi.ts
@@ -3436,6 +3719,22 @@ function getInstantPanchang(date, location, options) {
3436
3719
  maxIter
3437
3720
  );
3438
3721
  }
3722
+ const t = getTranslations(lang);
3723
+ const specialYogas = computeSpecialYogas(
3724
+ vara.index,
3725
+ tithi.index,
3726
+ Math.floor(siderealMoon / NAKSHATRA_SPAN),
3727
+ (type) => t.specialYogaNames[type] ?? type
3728
+ );
3729
+ const festivals = computeFestivals(
3730
+ tithi.index,
3731
+ Math.floor(siderealMoon / NAKSHATRA_SPAN),
3732
+ chandramasa.index,
3733
+ chandramasa.isAdhika,
3734
+ vara.index,
3735
+ siderealSun,
3736
+ (key) => t.festivalNames[key] ?? t.misc[key] ?? key
3737
+ );
3439
3738
  return {
3440
3739
  timestamp: date,
3441
3740
  location,
@@ -3451,7 +3750,9 @@ function getInstantPanchang(date, location, options) {
3451
3750
  samvat,
3452
3751
  chandraRashi,
3453
3752
  suryaNakshatra,
3454
- panchaka: computePanchaka(siderealMoon)
3753
+ panchaka: computePanchaka(siderealMoon),
3754
+ specialYogas,
3755
+ festivals
3455
3756
  };
3456
3757
  }
3457
3758
  function getDailyPanchang(date, location, options) {
@@ -3522,9 +3823,33 @@ function getDailyPanchang(date, location, options) {
3522
3823
  vara.index,
3523
3824
  (idx) => getTranslations(lang).grahaNames[idx]
3524
3825
  );
3826
+ const gowriPanchangam = computeGowriPanchangam(
3827
+ sunriseUtc,
3828
+ sunsetUtc,
3829
+ nextSunriseUtc,
3830
+ vara.index,
3831
+ (idx) => getTranslations(lang).gowriNames[idx]
3832
+ );
3525
3833
  const moonriseUtc = getMoonrise(localMidnightUtc, location);
3526
3834
  const moonsetUtc = getMoonset(localMidnightUtc, location);
3527
3835
  const panchaka = computePanchaka(siderealMoonAtSunrise);
3836
+ const t = getTranslations(lang);
3837
+ const specialYogas = computeSpecialYogas(
3838
+ vara.index,
3839
+ tithiAtSunrise.index,
3840
+ Math.floor(siderealMoonAtSunrise / NAKSHATRA_SPAN),
3841
+ (type) => t.specialYogaNames[type] ?? type
3842
+ );
3843
+ const durMuhurtaUtc = computeDurMuhurta(sunriseUtc, sunsetUtc, vara.index);
3844
+ const festivals = computeFestivals(
3845
+ tithiAtSunrise.index,
3846
+ Math.floor(siderealMoonAtSunrise / NAKSHATRA_SPAN),
3847
+ chandramasa.index,
3848
+ chandramasa.isAdhika,
3849
+ vara.index,
3850
+ siderealSunAtSunrise,
3851
+ (key) => t.festivalNames[key] ?? t.misc[key] ?? key
3852
+ );
3528
3853
  let tithis;
3529
3854
  let nakshatras;
3530
3855
  let yogas;
@@ -3604,9 +3929,9 @@ function getDailyPanchang(date, location, options) {
3604
3929
  });
3605
3930
  const dayDurationMs = sunsetUtc.getTime() - sunriseUtc.getTime();
3606
3931
  const nightDurationMs = nextSunriseUtc.getTime() - sunsetUtc.getTime();
3607
- for (const t of tithis) {
3608
- t.endTime = toLocalOrNull(t.endTime);
3609
- t.startTime = toLocalOrNull(t.startTime);
3932
+ for (const t2 of tithis) {
3933
+ t2.endTime = toLocalOrNull(t2.endTime);
3934
+ t2.startTime = toLocalOrNull(t2.startTime);
3610
3935
  }
3611
3936
  for (const n of nakshatras) {
3612
3937
  n.endTime = toLocalOrNull(n.endTime);
@@ -3657,7 +3982,14 @@ function getDailyPanchang(date, location, options) {
3657
3982
  },
3658
3983
  moonrise: moonriseUtc ? toLocal(moonriseUtc) : null,
3659
3984
  moonset: moonsetUtc ? toLocal(moonsetUtc) : null,
3660
- panchaka
3985
+ panchaka,
3986
+ specialYogas,
3987
+ durMuhurta: [convertTimePeriod(durMuhurtaUtc[0]), convertTimePeriod(durMuhurtaUtc[1])],
3988
+ festivals,
3989
+ gowriPanchangam: {
3990
+ day: gowriPanchangam.day.map((s) => ({ ...s, ...convertTimePeriod(s) })),
3991
+ night: gowriPanchangam.night.map((s) => ({ ...s, ...convertTimePeriod(s) }))
3992
+ }
3661
3993
  };
3662
3994
  }
3663
3995
  /*! Bundled license information:
@@ -3698,4 +4030,4 @@ astronomy-engine/esm/astronomy.js:
3698
4030
  *)
3699
4031
  */
3700
4032
 
3701
- export { PanchangError, computeAbhijitMuhurta, computeBrahmaMuhurta, computeGulikaKalam, computeRahuKalam, computeYamaganda, computeAyanamsa as getAyanamsa, getDailyPanchang, getInstantPanchang, getMoonrise, getMoonset, getSiderealMoonLongitude, getSiderealSunLongitude, computeSunrise as getSunrise, computeSunset as getSunset };
4033
+ export { PanchangError, computeAbhijitMuhurta, computeBrahmaMuhurta, computeGowriPanchangam, computeGulikaKalam, computeRahuKalam, computeYamaganda, computeAyanamsa as getAyanamsa, getDailyPanchang, getInstantPanchang, getMoonrise, getMoonset, getSiderealMoonLongitude, getSiderealSunLongitude, computeSunrise as getSunrise, computeSunset as getSunset };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "panchang-ts",
3
- "version": "0.2.2",
3
+ "version": "0.3.1",
4
4
  "description": "Pure TypeScript Hindu Panchang calculations. Tithi, Nakshatra, Yoga, Karana, Vara, and more. Offline-first, React Native compatible.",
5
5
  "author": "Ishank",
6
6
  "license": "MIT",