Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
245 changes: 185 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,103 +1,229 @@
# @af/sweph Monorepo
# @af/sweph

The ultimate Swiss Ephemeris library for Vedic Astrology, supporting Node.js, Browser (WASM), and React Native with a unified API.

[![CI](https://github.com/astro-fusion/af-sweph/actions/workflows/ci.yml/badge.svg)](https://github.com/astro-fusion/af-sweph/actions/workflows/ci.yml)
[![Build](https://github.com/astro-fusion/af-sweph/actions/workflows/build.yml/badge.svg)](https://github.com/astro-fusion/af-sweph/actions/workflows/build.yml)

## 🌟 Multi-Platform Architecture
## 🌟 Features

This library is architected as a monorepo to provide optimized implementations for every target platform while maintaining a consistent developer experience.
- **✅ Auto-initialization** - Native module loads automatically
- **✅ TypeScript First** - Complete type safety with IntelliSense
- **✅ Vedic Astrology** - Ayanamsa, Rashis, Nakshatras built-in
- **✅ Multi-Platform** - Node.js, Browser (WASM), React Native
- **✅ Vercel Ready** - Pre-built binaries for serverless

| Package | Environment | Core Technology | Description |
|---------|-------------|-----------------|-------------|
| [`@af/sweph-core`](./packages/core) | All | TypeScript | Shared logic, interfaces, and pure JS utilities. |
| [`@af/sweph-node`](./packages/node) | Node.js | Native C++ | High-performance implementation using native binaries. |
| [`@af/sweph-wasm`](./packages/wasm) | Browser | WebAssembly | Optimized for web with async loading support. |
| [`@af/sweph-react-native`](./packages/react-native) | Mobile | JSI/Turbo Modules | Native iOS and Android implementation. |
## 🚀 Quick Start

---

## 🚀 Quick Start (Unified API)

Regardless of the platform, the API remains consistent via the `ISwephInstance` interface.

### 1. Installation

Pick the package for your target platform:
### Installation

```bash
# For Node.js / Serverless (Vercel)
pnpm add @af/sweph-node
# npm
npm install @af/sweph

# For Browser applications
pnpm add @af/sweph-wasm
# pnpm
pnpm add @af/sweph

# For React Native applications
pnpm add @af/sweph-react-native
# Or from GitHub
pnpm add github:astro-fusion/af-sweph
```

### 2. Usage Example
### Usage

```typescript
import { createSweph } from '@af/sweph-node'; // Or @af/sweph-wasm / @af/sweph-react-native
import { createSweph, AYANAMSA } from '@af/sweph';

async function run() {
// 1. Initialize the instance
async function main() {
// Create instance (auto-initializes native module)
const sweph = await createSweph();

// 2. Perform calculations
const date = new Date();
const planets = sweph.calculatePlanets(date, {
ayanamsa: 1, // Lahiri
location: { latitude: 27.7, longitude: 85.3 }
// Calculate planetary positions
const planets = await sweph.calculatePlanets(new Date(), {
ayanamsa: AYANAMSA.LAHIRI,
timezone: 5.75, // Nepal
});

console.log(planets);
console.log('Sun:', planets.find(p => p.id === 'sun'));
console.log('Moon:', planets.find(p => p.id === 'moon'));

// Calculate Lagna (Ascendant)
const lagna = await sweph.calculateLagna(
new Date(),
{ latitude: 27.7, longitude: 85.3, timezone: 5.75 },
{ ayanamsa: AYANAMSA.LAHIRI }
);

console.log('Ascendant:', lagna.longitude, 'in', sweph.RASHIS[lagna.rasi]);

// Calculate Moon Phase
const moonPhase = await sweph.calculateMoonPhase(new Date());
console.log('Moon Phase:', moonPhase.phaseName, `(${Math.round(moonPhase.illumination * 100)}%)`);
}

main();
Comment on lines +36 to +66

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The usage example in main() calls new Date() multiple times. For astrological calculations, it's crucial that all computations refer to the exact same moment in time. Using new Date() repeatedly introduces slight time differences between calls, which can lead to inconsistent results.

It's better to define the date once and reuse it for all calculations. For example:

async function main() {
  const sweph = await createSweph();
  const calculationDate = new Date();

  const planets = await sweph.calculatePlanets(calculationDate, ...);
  const lagna = await sweph.calculateLagna(calculationDate, ...);
  const moonPhase = await sweph.calculateMoonPhase(calculationDate);
  // ...
}

```

---

## 📦 Packages
## 📦 API Reference

### `createSweph(options?): Promise<SwephInstance>`

Creates an auto-initialized Swiss Ephemeris instance.

```typescript
const sweph = await createSweph({
ephePath: '/path/to/ephemeris', // Optional: custom ephemeris path
preWarm: true, // Optional: pre-calculate to warm cache
});
```

### SwephInstance Methods

#### Planetary Calculations

```typescript
// All 9 Vedic planets
const planets = await sweph.calculatePlanets(date, {
ayanamsa: 1, // Lahiri

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve readability and prevent errors from using magic numbers, it's better to use the AYANAMSA constant. This makes the code self-documenting and is consistent with other examples in the README.

Suggested change
ayanamsa: 1, // Lahiri
ayanamsa: AYANAMSA.LAHIRI, // Lahiri

timezone: 0, // UTC
});

// Single planet (0=Sun, 1=Moon, 2=Mars, etc.)
const sun = await sweph.calculatePlanet(0, date, { ayanamsa: 1 });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For consistency and better readability, please use the AYANAMSA constant instead of the magic number 1.

Suggested change
const sun = await sweph.calculatePlanet(0, date, { ayanamsa: 1 });
const sun = await sweph.calculatePlanet(0, date, { ayanamsa: AYANAMSA.LAHIRI });


// Rise, Set, Transit times
const riseSet = await sweph.calculateRiseSet(0, date, {
latitude: 27.7,
longitude: 85.3,
});
```

#### Lagna & Houses

```typescript
const lagna = await sweph.calculateLagna(
date,
{ latitude: 27.7, longitude: 85.3 },
{ ayanamsa: 1 }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the AYANAMSA constant is preferred over the magic number 1 for clarity and consistency.

Suggested change
{ ayanamsa: 1 }
{ ayanamsa: AYANAMSA.LAHIRI }

);

console.log(lagna.longitude); // Ascendant in degrees
console.log(lagna.rasi); // Ascendant sign (1-12)
console.log(lagna.houses); // Array of 12 house cusps
```

#### Sun Calculations

```typescript
// Sunrise, Sunset, Solar Noon
const sunTimes = await sweph.calculateSunTimes(date, location);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The location variable is used here without being defined, which will cause an error for users who copy this example. Please define it before use. This applies to the other examples in the 'Sun Calculations' and 'Moon Calculations' sections as well.

For example:

const date = new Date();
const location = { latitude: 27.7, longitude: 85.3 };
const sunTimes = await sweph.calculateSunTimes(date, location);


// Solar Noon with altitude
const noon = await sweph.calculateSolarNoon(date, location);

### [@af/sweph-core](./packages/core)
The backbone of the library. Contains all shared types, constant definitions (Planet IDs, Ayanamsas), and pure JavaScript utilities that don't depend on a native environment.
// Sun path throughout the day
const path = await sweph.calculateSunPath(date, location);
```

#### Moon Calculations

```typescript
// Moon data (position, rise/set, phase)
const moonData = await sweph.calculateMoonData(date, location);

// Current moon phase
const phase = await sweph.calculateMoonPhase(date);
console.log(phase.phaseName); // "Waxing Crescent", "Full Moon", etc.
console.log(phase.illumination); // 0.0 to 1.0

// Next moon phases
const nextPhases = await sweph.calculateNextMoonPhases(date);
console.log('Next New Moon:', nextPhases.newMoon);
console.log('Next Full Moon:', nextPhases.fullMoon);
```

#### Utilities

```typescript
// Get ayanamsa value
const ayanamsa = sweph.getAyanamsa(date, AYANAMSA.LAHIRI);

### [@af/sweph-node](./packages/node)
The successor to the original `@af/sweph`. It includes pre-built binaries for Linux, macOS, and Windows. It is specifically optimized for **Vercel** and other serverless environments, requiring zero native compilation at deploy time.
// Convert to Julian Day
const jd = sweph.dateToJulian(date);

### [@af/sweph-wasm](./packages/wasm)
A WebAssembly-powered implementation designed for browser environments. It handles the async loading of the `.wasm` binary and provides a type-safe wrapper. Perfect for static sites or client-side calculation needs.
// Set ephemeris path
sweph.setEphePath('/custom/path/to/ephe');
```

### [@af/sweph-react-native](./packages/react-native)
Utilizes **Turbo Modules** and **JSI** to bridge the Swiss Ephemeris C library directly into React Native. This provides near-native performance on both iOS and Android without crossing the traditional asynchronous bridge.
### Constants

```typescript
import { PLANETS, AYANAMSA, RASHIS, NAKSHATRAS } from '@af/sweph';

// Planet IDs
PLANETS.SUN; // 0
PLANETS.MOON; // 1
PLANETS.MARS; // 4
PLANETS.MERCURY; // 2
PLANETS.JUPITER; // 5
PLANETS.VENUS; // 3
PLANETS.SATURN; // 6
PLANETS.RAHU; // 10
PLANETS.KETU; // 11

// Ayanamsa types
AYANAMSA.LAHIRI; // 1 (default)
AYANAMSA.KRISHNAMURTI; // 5
AYANAMSA.RAMAN; // 3

// Rashi names
RASHIS[1]; // "Aries"
RASHIS[4]; // "Cancer"
RASHIS[10]; // "Capricorn"

// Nakshatra names
NAKSHATRAS[1]; // "Ashwini"
NAKSHATRAS[14]; // "Chitra"
NAKSHATRAS[27]; // "Revati"
```

---

## 🛠 Features
## 🏗️ Multi-Platform Architecture

- **✅ Universal Compatibility** - Node, Browser, iOS, and Android.
- **✅ Vercel Ready** - Pre-built binaries for serverless environments.
- **✅ TypeScript First** - Complete type safety for all astrological entities.
- **✅ Vedic Centric** - Native support for Ayanamsas, Rashis, and Nakshatras.
- **✅ Unified Interface** - Write your business logic once, run it anywhere.
| Package | Environment | Technology |
|---------|-------------|------------|
| `@af/sweph-node` | Node.js | Native C++ bindings |
| `@af/sweph-wasm` | Browser | WebAssembly |
| `@af/sweph-react-native` | Mobile | JSI/Turbo Modules |
| `@af/sweph-core` | All | Shared TypeScript |

## 🤝 Contributing
---

This is a monorepo managed with `pnpm`.
## 🐛 Troubleshooting

### Module not found on Vercel

Ensure pre-built binaries are installed:
```bash
# Clone
git clone https://github.com/astro-fusion/af-sweph
ls node_modules/@af/sweph/prebuilds/
# Should show: linux-x64/
```

# Install
pnpm install
### Native module errors

# Build all packages
pnpm -r build
Set `NODE_VERSION=20` in your environment.

---

# Run tests
## 🤝 Contributing

```bash
git clone https://github.com/astro-fusion/af-sweph
cd af-sweph
pnpm install
pnpm -r build
pnpm -r test
```

Expand All @@ -107,5 +233,4 @@ MIT

## ❤️ Credits

- [Swiss Ephemeris](https://www.astro.com/swisseph/) by Astrodienst AG.
- [swisseph-v2](https://github.com/nickhealthy/swisseph-v2) for initial Node.js bindings.
- [Swiss Ephemeris](https://www.astro.com/swisseph/) by Astrodienst AG
1 change: 0 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
".": {
"types": "./dist/index.d.ts",
"require": "./dist/index.js",
"import": "./dist/index.mjs",
"default": "./dist/index.js"
}
},
Expand Down
37 changes: 33 additions & 4 deletions packages/node/dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,44 @@
* @AstroFusion/sweph - Swiss Ephemeris for Vedic Astrology
*
* This is the main entry point for the library.
* All public APIs are exported from here.
*
* ## v2 API (Recommended)
* ```typescript
* import { createSweph } from '@af/sweph';
*
* const sweph = await createSweph();
* const planets = await sweph.calculatePlanets(new Date(), { ayanamsa: 1 });
* ```
*
* ## Legacy API (Deprecated)
* ```typescript
* import { initializeSweph, createSwephAdapter } from '@af/sweph';
*
* await initializeSweph();
* const adapter = await createSwephAdapter();
* ```
*/
export * from './types';
export { createSweph, type SwephInstance, type SwephInitOptions, type Location, type PlanetOptions, type AstroOptions, type RiseSetTransit, } from './v2';
export { calculatePlanets, calculateSinglePlanet, calculatePlanetRiseSetTimes, } from './planets';
export { calculateLagna, calculateHouses, } from './houses';
export { calculateSunTimes, calculateSolarNoon, calculateSunPath, } from './sun';
export { calculateMoonData, calculateMoonPhase, calculateNextMoonPhases, } from './moon';
export { getAyanamsa, setEphemerisPath, getJulianDay, dateToJulian, julianToDate, getNativeModule, } from './utils';
export { getAyanamsa, setEphemerisPath, getJulianDay, dateToJulian, julianToDate, getNativeModule, initializeSweph, } from './utils';
export { getPlatformInfo, hasPrebuilds, getSupportedPlatforms, } from './native-loader';
export { PLANETS, AYANAMSA, HOUSE_SYSTEMS, RASHIS, NAKSHATRAS, VEDIC_PLANET_ORDER, } from './constants';
export { createSwephCalculator, createPlanetaryCalculator, createSwephAdapter, createNodeAdapter, initializeSweph, registerAdapter, calculateKundaliPageData, type PlanetaryCalculationProvider, type SwephAdapter, type SunTimesResult, type MoonTimesResult, type LegacyPlanet, type LegacyLagnaInfo, } from './legacy';
export type { Planet, GeoLocation, SunTimes, MoonData, MoonPhase, LagnaInfo, NextMoonPhases, CalculationOptions, } from './types';
export { PlanetId, AyanamsaType, HouseSystem, } from './types';
export {
/** @deprecated Use createSweph() instead */
createSwephCalculator,
/** @deprecated Use createSweph() instead */
createPlanetaryCalculator,
/** @deprecated Use createSweph() instead */
createSwephAdapter,
/** @deprecated Use createSweph() instead */
createNodeAdapter,
/** @deprecated No longer needed - createSweph() auto-initializes */
registerAdapter,
/** @deprecated Use individual calculation methods */
calculateKundaliPageData, type PlanetaryCalculationProvider, type SwephAdapter, type SunTimesResult, type MoonTimesResult, type LegacyPlanet, type LegacyLagnaInfo, } from './legacy';
//# sourceMappingURL=index.d.ts.map
2 changes: 1 addition & 1 deletion packages/node/dist/index.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading