@aulunarcana/ephemeris 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +46 -0
- package/README.md +146 -0
- package/index.d.ts +158 -0
- package/index.mjs +243 -0
- package/package.json +21 -0
- package/pkg/LICENSE +46 -0
- package/pkg/ephemeris_wasm.d.ts +36 -0
- package/pkg/ephemeris_wasm.js +218 -0
- package/pkg/ephemeris_wasm_bg.wasm +0 -0
- package/pkg/ephemeris_wasm_bg.wasm.d.ts +14 -0
- package/pkg/package.json +13 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
AuLun Ephemeris — Proprietary License
|
|
2
|
+
Free for Non-Commercial Use
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2026 AuLun Arcana LLC. All rights reserved.
|
|
5
|
+
|
|
6
|
+
This license governs the compiled AuLun Ephemeris package (the
|
|
7
|
+
"Software"): the WASM binary, the JavaScript/TypeScript wrapper, and
|
|
8
|
+
the embedded astronomical data as distributed. Source code is not
|
|
9
|
+
included and is not licensed.
|
|
10
|
+
|
|
11
|
+
1. NON-COMMERCIAL GRANT. You may install and use the Software free of
|
|
12
|
+
charge for personal, educational, research, and other
|
|
13
|
+
non-commercial purposes. "Non-commercial" excludes any use in or
|
|
14
|
+
for a product, service, or activity that is sold, monetized, or
|
|
15
|
+
operated for commercial advantage, whether or not for profit.
|
|
16
|
+
|
|
17
|
+
2. COMMERCIAL USE. Any commercial use requires a separate commercial
|
|
18
|
+
license from the copyright holder. Contact:
|
|
19
|
+
https://github.com/routerbad
|
|
20
|
+
|
|
21
|
+
3. RESTRICTIONS. You may not (a) redistribute, sublicense, sell, or
|
|
22
|
+
host the Software for use by third parties except as an
|
|
23
|
+
incidental, non-separable part of a permitted non-commercial
|
|
24
|
+
application; (b) modify, adapt, or create derivative works of the
|
|
25
|
+
Software; (c) reverse engineer, decompile, or disassemble the
|
|
26
|
+
Software, or extract its embedded implementation, except to the
|
|
27
|
+
extent applicable law expressly permits despite this limitation;
|
|
28
|
+
(d) remove or alter proprietary notices.
|
|
29
|
+
|
|
30
|
+
4. DATA. The astronomical data embedded in the Software derives from
|
|
31
|
+
public-domain and factual sources (documented by the copyright
|
|
32
|
+
holder); nothing in this license restricts your independent use of
|
|
33
|
+
those underlying public sources.
|
|
34
|
+
|
|
35
|
+
5. OWNERSHIP. The Software is licensed, not sold. The copyright
|
|
36
|
+
holder retains all rights not expressly granted.
|
|
37
|
+
|
|
38
|
+
6. TERMINATION. This license terminates automatically if you breach
|
|
39
|
+
it. Upon termination you must cease use and destroy copies.
|
|
40
|
+
|
|
41
|
+
7. NO WARRANTY. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
|
42
|
+
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
43
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, AND
|
|
44
|
+
NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE
|
|
45
|
+
FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM THE USE OF
|
|
46
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# @aulunarcana/ephemeris
|
|
2
|
+
|
|
3
|
+
AuLun Ephemeris — an astronomical ephemeris and natal chart engine
|
|
4
|
+
compiled to WebAssembly. Sub-arcsecond accuracy validated against JPL
|
|
5
|
+
Horizons across 1900–2100 (Moon median 0.06″). **Free for
|
|
6
|
+
non-commercial use**; commercial licenses available (see License
|
|
7
|
+
below).
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @aulunarcana/ephemeris
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Node 18+. Self-contained — all ephemeris data (~13 MB) is embedded.
|
|
16
|
+
|
|
17
|
+
## Quick start — tropical zodiac, Placidus houses
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
import { Ephemeris, degreesToRadians, radiansToDegrees } from "@aulunarcana/ephemeris";
|
|
21
|
+
|
|
22
|
+
const engine = new Ephemeris(); // parses embedded data once — construct once, reuse
|
|
23
|
+
|
|
24
|
+
const chart = engine.computeChart(
|
|
25
|
+
{ year: 1990, month: 6, day: 15, hour: 21, minute: 30 }, // local civil time
|
|
26
|
+
"America/Los_Angeles", // IANA timezone
|
|
27
|
+
{ latitudeRad: degreesToRadians(34.05), longitudeRad: degreesToRadians(-118.24) },
|
|
28
|
+
{ houseSystem: "placidus" }, // tropical is the default zodiac
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
radiansToDegrees(chart.ascendantRad); // Ascendant
|
|
32
|
+
chart.bodies.sun.longitudeRad; // apparent ecliptic longitude
|
|
33
|
+
chart.bodies.moon.longitudeRateRadPerDay; // negative = retrograde
|
|
34
|
+
chart.houses.cuspsRad; // the 12 Placidus cusps
|
|
35
|
+
chart.aspects; // aspects with applying/separating
|
|
36
|
+
chart.patterns; // grand trines, T-squares, …
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
All angles are radians; convert with `radiansToDegrees` /
|
|
40
|
+
`degreesToRadians`. The full result shape is in `index.d.ts`
|
|
41
|
+
(`Chart`).
|
|
42
|
+
|
|
43
|
+
## What a chart contains
|
|
44
|
+
|
|
45
|
+
- **Bodies** (`chart.bodies`): `sun`, `moon`, `mercury`, `venus`,
|
|
46
|
+
`mars`, `jupiter`, `saturn`, `uranus`, `neptune`, `pluto`,
|
|
47
|
+
`chiron` — each with apparent ecliptic longitude, latitude,
|
|
48
|
+
distance, and daily motion (negative = retrograde).
|
|
49
|
+
- **Angles and houses**: Ascendant, Midheaven, 12 house cusps.
|
|
50
|
+
- **Lunar points**: mean and true North/South Node and Lilith.
|
|
51
|
+
- **Hermetic lots**: Fortune, Spirit, Eros, Necessity, Courage,
|
|
52
|
+
Victory, Nemesis (day/night sect handled via `isDayChart`).
|
|
53
|
+
- **Aspects**: major and minor aspects with orb, exact angle, and
|
|
54
|
+
applying/separating; plus detected patterns (grand trine,
|
|
55
|
+
T-square, …).
|
|
56
|
+
|
|
57
|
+
## House systems
|
|
58
|
+
|
|
59
|
+
Pass one of these as `houseSystem` (default: `"placidus"`):
|
|
60
|
+
|
|
61
|
+
| Value | System |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `"placidus"` | Placidus |
|
|
64
|
+
| `"koch"` | Koch |
|
|
65
|
+
| `"whole_sign"` | Whole Sign |
|
|
66
|
+
| `"equal"` | Equal |
|
|
67
|
+
| `"porphyry"` | Porphyry |
|
|
68
|
+
| `"regiomontanus"` | Regiomontanus |
|
|
69
|
+
| `"campanus"` | Campanus |
|
|
70
|
+
| `"alcabitius"` | Alcabitius |
|
|
71
|
+
| `"topocentric"` | Topocentric (Polich–Page) |
|
|
72
|
+
| `"morinus"` | Morinus |
|
|
73
|
+
| `"meridian"` | Meridian (Axial) |
|
|
74
|
+
|
|
75
|
+
## Zodiac: tropical and sidereal (Vedic)
|
|
76
|
+
|
|
77
|
+
Every chart is computed in the **tropical** zodiac. To also get
|
|
78
|
+
sidereal values, pass an `ayanamsa`:
|
|
79
|
+
|
|
80
|
+
| Value | Tradition |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `"lahiri"` | Vedic / Jyotish standard (Chitrapaksha) |
|
|
83
|
+
| `"fagan_bradley"` | Western sidereal |
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
const vedic = engine.computeChart(civil, zone, observer, {
|
|
87
|
+
houseSystem: "whole_sign",
|
|
88
|
+
ayanamsa: "lahiri",
|
|
89
|
+
});
|
|
90
|
+
vedic.bodies.moon.siderealLongitudeRad; // sidereal position
|
|
91
|
+
vedic.siderealHouses.cuspsRad; // sidereal cusps
|
|
92
|
+
vedic.ayanamsaRad; // the ayanamsa applied
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Sidereal output is additive — the tropical fields are always present.
|
|
96
|
+
|
|
97
|
+
## Extended minor bodies (optional)
|
|
98
|
+
|
|
99
|
+
Sixteen additional bodies are supported but not embedded: `ceres`,
|
|
100
|
+
`pallas`, `juno`, `vesta`, `eris`, `sedna`, `haumea`, `makemake`,
|
|
101
|
+
`quaoar`, `orcus`, `varuna`, `ixion`, `gonggong`, `pholus`, `nessus`,
|
|
102
|
+
`chariklo`. Load a body's data table first, then request it:
|
|
103
|
+
|
|
104
|
+
```js
|
|
105
|
+
engine.loadMinorBodyTable("ceres", ceresTableText);
|
|
106
|
+
const chart = engine.computeChart(civil, zone, observer, {
|
|
107
|
+
includeMinorBodies: ["ceres"],
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
A requested body whose table isn't loaded (or whose date is outside
|
|
112
|
+
table coverage) is listed in `chart.outOfRange` instead of failing
|
|
113
|
+
the chart.
|
|
114
|
+
|
|
115
|
+
## Time handling
|
|
116
|
+
|
|
117
|
+
`computeChart` takes naive civil time plus an IANA zone and resolves
|
|
118
|
+
DST correctly:
|
|
119
|
+
|
|
120
|
+
- Ambiguous local times (DST fall-back) throw
|
|
121
|
+
`AmbiguousLocalTimeError` unless you pass `fold` (`0` = earlier
|
|
122
|
+
instant, `1` = later).
|
|
123
|
+
- Nonexistent local times (spring-forward gap) always throw
|
|
124
|
+
`NonexistentLocalTimeError`.
|
|
125
|
+
|
|
126
|
+
If you already have UTC, use
|
|
127
|
+
`engine.computeChartUtc(utc, observer, options)` and skip timezone
|
|
128
|
+
resolution entirely.
|
|
129
|
+
|
|
130
|
+
## Accuracy
|
|
131
|
+
|
|
132
|
+
Apparent positions are computed from VSOP87E, ELP/MPP02, and
|
|
133
|
+
JPL-derived state vectors with full IAU 2000A/2006 precession-
|
|
134
|
+
nutation, light-time, and relativistic aberration. Validated against
|
|
135
|
+
JPL Horizons over 1900–2100: sub-arcsecond median accuracy for every
|
|
136
|
+
supported body.
|
|
137
|
+
|
|
138
|
+
## License
|
|
139
|
+
|
|
140
|
+
Proprietary. **Free for non-commercial use** — personal, educational,
|
|
141
|
+
and research use is free of charge under the LICENSE shipped with
|
|
142
|
+
this package. Use in or for anything sold, monetized, or operated for
|
|
143
|
+
commercial advantage requires a commercial license: contact the
|
|
144
|
+
copyright holder via https://github.com/AuLunArcana.
|
|
145
|
+
|
|
146
|
+
© 2026 AuLun Arcana LLC. All rights reserved.
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/** Type surface for @aulunarcana/ephemeris. All angles are radians
|
|
2
|
+
* unless a name says otherwise; use radiansToDegrees for display. */
|
|
3
|
+
|
|
4
|
+
export interface CivilTime {
|
|
5
|
+
year: number;
|
|
6
|
+
month: number;
|
|
7
|
+
day: number;
|
|
8
|
+
hour: number;
|
|
9
|
+
minute: number;
|
|
10
|
+
second?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface UtcFields {
|
|
14
|
+
year: number;
|
|
15
|
+
month: number;
|
|
16
|
+
day: number;
|
|
17
|
+
hour: number;
|
|
18
|
+
minute: number;
|
|
19
|
+
second: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface Observer {
|
|
23
|
+
latitudeRad: number;
|
|
24
|
+
longitudeRad: number;
|
|
25
|
+
heightM?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type HouseSystem =
|
|
29
|
+
| "whole_sign"
|
|
30
|
+
| "equal"
|
|
31
|
+
| "porphyry"
|
|
32
|
+
| "meridian"
|
|
33
|
+
| "regiomontanus"
|
|
34
|
+
| "campanus"
|
|
35
|
+
| "alcabitius"
|
|
36
|
+
| "placidus"
|
|
37
|
+
| "koch"
|
|
38
|
+
| "topocentric"
|
|
39
|
+
| "morinus";
|
|
40
|
+
|
|
41
|
+
export type Ayanamsa = "lahiri" | "fagan_bradley";
|
|
42
|
+
|
|
43
|
+
export interface ChartOptions {
|
|
44
|
+
houseSystem?: HouseSystem;
|
|
45
|
+
includeMinorBodies?: string[];
|
|
46
|
+
ayanamsa?: Ayanamsa;
|
|
47
|
+
/** null rejects ambiguous local times; 0 = earlier, 1 = later. */
|
|
48
|
+
fold?: 0 | 1 | null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface BodyPosition {
|
|
52
|
+
longitudeRad: number;
|
|
53
|
+
latitudeRad: number;
|
|
54
|
+
distanceAu: number;
|
|
55
|
+
longitudeRateRadPerDay: number;
|
|
56
|
+
siderealLongitudeRad: number | null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface Houses {
|
|
60
|
+
ascendantRad: number;
|
|
61
|
+
midheavenRad: number;
|
|
62
|
+
cuspsRad: number[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface AspectHit {
|
|
66
|
+
bodyA: string;
|
|
67
|
+
bodyB: string;
|
|
68
|
+
aspect: string;
|
|
69
|
+
exactAngleRad: number;
|
|
70
|
+
separationRad: number;
|
|
71
|
+
orbRad: number;
|
|
72
|
+
applying: boolean | null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface PatternHit {
|
|
76
|
+
pattern: string;
|
|
77
|
+
bodies: string[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface LunarPoints {
|
|
81
|
+
meanNodeRad: number;
|
|
82
|
+
trueNodeRad: number;
|
|
83
|
+
meanSouthNodeRad: number;
|
|
84
|
+
trueSouthNodeRad: number;
|
|
85
|
+
meanLilithRad: number;
|
|
86
|
+
trueLilithRad: number;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface Lots {
|
|
90
|
+
fortune: number;
|
|
91
|
+
spirit: number;
|
|
92
|
+
eros: number;
|
|
93
|
+
necessity: number;
|
|
94
|
+
courage: number;
|
|
95
|
+
victory: number;
|
|
96
|
+
nemesis: number;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface Chart {
|
|
100
|
+
jdUtc: number;
|
|
101
|
+
jdTt: number;
|
|
102
|
+
houseSystem: string;
|
|
103
|
+
ayanamsaName: string | null;
|
|
104
|
+
ayanamsaRad: number | null;
|
|
105
|
+
bodies: Record<string, BodyPosition>;
|
|
106
|
+
outOfRange: string[];
|
|
107
|
+
ascendantRad: number;
|
|
108
|
+
midheavenRad: number;
|
|
109
|
+
houses: Houses;
|
|
110
|
+
siderealHouses: Houses | null;
|
|
111
|
+
lunarPoints: LunarPoints;
|
|
112
|
+
isDayChart: boolean;
|
|
113
|
+
lots: Lots;
|
|
114
|
+
aspects: AspectHit[];
|
|
115
|
+
patterns: PatternHit[];
|
|
116
|
+
utc?: UtcFields;
|
|
117
|
+
ianaZone?: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export class AmbiguousLocalTimeError extends Error {}
|
|
121
|
+
export class NonexistentLocalTimeError extends Error {}
|
|
122
|
+
|
|
123
|
+
export function resolveCivilToUtc(
|
|
124
|
+
local: CivilTime,
|
|
125
|
+
zone: string,
|
|
126
|
+
fold?: 0 | 1 | null,
|
|
127
|
+
): UtcFields;
|
|
128
|
+
|
|
129
|
+
export function radiansToDegrees(rad: number): number;
|
|
130
|
+
export function degreesToRadians(deg: number): number;
|
|
131
|
+
|
|
132
|
+
export interface BodyPositionLite {
|
|
133
|
+
longitudeRad: number;
|
|
134
|
+
latitudeRad: number;
|
|
135
|
+
distanceAu: number;
|
|
136
|
+
longitudeRateRadPerDay: number;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface BodyPositions {
|
|
140
|
+
jdUtc: number;
|
|
141
|
+
jdTt: number;
|
|
142
|
+
bodies: Record<string, BodyPositionLite>;
|
|
143
|
+
outOfRange: string[];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export class Ephemeris {
|
|
147
|
+
constructor();
|
|
148
|
+
loadMinorBodyTable(name: string, content: string): void;
|
|
149
|
+
computeChart(
|
|
150
|
+
civil: CivilTime,
|
|
151
|
+
zone: string,
|
|
152
|
+
observer: Observer,
|
|
153
|
+
options?: ChartOptions,
|
|
154
|
+
): Chart;
|
|
155
|
+
computeChartUtc(utc: UtcFields, observer: Observer, options?: ChartOptions): Chart;
|
|
156
|
+
/** Positions-only fast path for a subset of bodies (transit scans). */
|
|
157
|
+
computeBodies(utc: Omit<UtcFields, "second"> & { second?: number }, bodies: string[]): BodyPositions;
|
|
158
|
+
}
|
package/index.mjs
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @aulunarcana/ephemeris — JS/TS surface over the WASM engine.
|
|
3
|
+
*
|
|
4
|
+
* Civil-time resolution lives HERE (port design decision 1): the WASM
|
|
5
|
+
* core takes a resolved UTC instant. Resolution uses Temporal with
|
|
6
|
+
* explicit disambiguation when the runtime ships it, and otherwise an
|
|
7
|
+
* Intl.DateTimeFormat offset-prober implementing the same semantics as
|
|
8
|
+
* the Python prototype's resolve_civil_datetime_to_utc:
|
|
9
|
+
* - fold null on an ambiguous local time (DST fall-back): throws
|
|
10
|
+
* AmbiguousLocalTimeError; fold 0 selects the earlier UTC instant,
|
|
11
|
+
* fold 1 the later.
|
|
12
|
+
* - a nonexistent local time (spring-forward gap) throws
|
|
13
|
+
* NonexistentLocalTimeError regardless of fold.
|
|
14
|
+
* Conformance is tested against Python-generated fold vectors
|
|
15
|
+
* (test/fold_vectors.json).
|
|
16
|
+
*/
|
|
17
|
+
import { createRequire } from "node:module";
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
const wasm = require("./pkg/ephemeris_wasm.js");
|
|
20
|
+
|
|
21
|
+
export class AmbiguousLocalTimeError extends Error {}
|
|
22
|
+
export class NonexistentLocalTimeError extends Error {}
|
|
23
|
+
|
|
24
|
+
const DAY_MS = 86400000;
|
|
25
|
+
|
|
26
|
+
function wallFieldsAt(epochMs, zone) {
|
|
27
|
+
const dtf = new Intl.DateTimeFormat("en-US", {
|
|
28
|
+
timeZone: zone,
|
|
29
|
+
era: "short",
|
|
30
|
+
year: "numeric",
|
|
31
|
+
month: "2-digit",
|
|
32
|
+
day: "2-digit",
|
|
33
|
+
hour: "2-digit",
|
|
34
|
+
minute: "2-digit",
|
|
35
|
+
second: "2-digit",
|
|
36
|
+
hour12: false,
|
|
37
|
+
});
|
|
38
|
+
const parts = Object.fromEntries(
|
|
39
|
+
dtf.formatToParts(new Date(epochMs)).map((p) => [p.type, p.value]),
|
|
40
|
+
);
|
|
41
|
+
let year = Number(parts.year);
|
|
42
|
+
if (parts.era === "BC") year = 1 - year;
|
|
43
|
+
return {
|
|
44
|
+
year,
|
|
45
|
+
month: Number(parts.month),
|
|
46
|
+
day: Number(parts.day),
|
|
47
|
+
hour: Number(parts.hour) % 24, // some ICU builds format midnight as "24"
|
|
48
|
+
minute: Number(parts.minute),
|
|
49
|
+
second: Number(parts.second),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function fieldsAsUtcMs(f) {
|
|
54
|
+
// NOT Date.UTC(...): it silently remaps years 0-99 to 1900-1999
|
|
55
|
+
// (review finding). setUTCFullYear takes the year literally, so
|
|
56
|
+
// ancient/first-century dates resolve correctly, matching both the
|
|
57
|
+
// Python prototype and the Temporal path.
|
|
58
|
+
const d = new Date(0);
|
|
59
|
+
d.setUTCFullYear(f.year, f.month - 1, f.day);
|
|
60
|
+
d.setUTCHours(f.hour, f.minute, f.second ?? 0, 0);
|
|
61
|
+
return d.getTime();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function zoneOffsetMs(epochMs, zone) {
|
|
65
|
+
return fieldsAsUtcMs(wallFieldsAt(epochMs, zone)) - epochMs;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function msToUtcFields(epochMs) {
|
|
69
|
+
const d = new Date(epochMs);
|
|
70
|
+
return {
|
|
71
|
+
year: d.getUTCFullYear(),
|
|
72
|
+
month: d.getUTCMonth() + 1,
|
|
73
|
+
day: d.getUTCDate(),
|
|
74
|
+
hour: d.getUTCHours(),
|
|
75
|
+
minute: d.getUTCMinutes(),
|
|
76
|
+
second: d.getUTCSeconds(),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function resolveViaIntl(local, zone, fold) {
|
|
81
|
+
const guess = fieldsAsUtcMs(local);
|
|
82
|
+
// Probe the zone offset around the guess: any transition within a
|
|
83
|
+
// day of the target surfaces both candidate offsets.
|
|
84
|
+
const offsets = new Set([
|
|
85
|
+
zoneOffsetMs(guess - DAY_MS, zone),
|
|
86
|
+
zoneOffsetMs(guess, zone),
|
|
87
|
+
zoneOffsetMs(guess + DAY_MS, zone),
|
|
88
|
+
]);
|
|
89
|
+
const candidates = [];
|
|
90
|
+
for (const offset of offsets) {
|
|
91
|
+
const instant = guess - offset;
|
|
92
|
+
// Valid iff the round trip reproduces the requested wall time.
|
|
93
|
+
if (zoneOffsetMs(instant, zone) === offset) {
|
|
94
|
+
candidates.push(instant);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const unique = [...new Set(candidates)].sort((a, b) => a - b);
|
|
98
|
+
if (unique.length === 0) {
|
|
99
|
+
throw new NonexistentLocalTimeError(
|
|
100
|
+
`${JSON.stringify(local)} in ${zone} does not exist (DST spring-forward gap).`,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
if (unique.length === 1) {
|
|
104
|
+
return msToUtcFields(unique[0]);
|
|
105
|
+
}
|
|
106
|
+
if (fold === null || fold === undefined) {
|
|
107
|
+
throw new AmbiguousLocalTimeError(
|
|
108
|
+
`${JSON.stringify(local)} in ${zone} is ambiguous (DST fall-back); ` +
|
|
109
|
+
"pass fold 0 (earlier) or 1 (later) explicitly.",
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
return msToUtcFields(fold === 0 ? unique[0] : unique[unique.length - 1]);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function resolveViaTemporal(local, zone, fold) {
|
|
116
|
+
const plain = new Temporal.PlainDateTime(
|
|
117
|
+
local.year,
|
|
118
|
+
local.month,
|
|
119
|
+
local.day,
|
|
120
|
+
local.hour,
|
|
121
|
+
local.minute,
|
|
122
|
+
local.second ?? 0,
|
|
123
|
+
);
|
|
124
|
+
let zoned;
|
|
125
|
+
try {
|
|
126
|
+
zoned = plain.toZonedDateTime(zone, {
|
|
127
|
+
disambiguation:
|
|
128
|
+
fold === null || fold === undefined
|
|
129
|
+
? "reject"
|
|
130
|
+
: fold === 0
|
|
131
|
+
? "earlier"
|
|
132
|
+
: "later",
|
|
133
|
+
});
|
|
134
|
+
} catch (error) {
|
|
135
|
+
// Temporal's reject covers BOTH gap and ambiguity; a Python-style
|
|
136
|
+
// round-trip re-probe classifies which, and the gap case must
|
|
137
|
+
// throw even with an explicit fold.
|
|
138
|
+
return classifyRejection(local, zone, fold);
|
|
139
|
+
}
|
|
140
|
+
// Temporal resolves gap times under earlier/later; Python raises for
|
|
141
|
+
// gaps regardless of fold. Round-trip check preserves that contract.
|
|
142
|
+
const roundTrip = zoned.toPlainDateTime();
|
|
143
|
+
if (
|
|
144
|
+
roundTrip.year !== plain.year ||
|
|
145
|
+
roundTrip.month !== plain.month ||
|
|
146
|
+
roundTrip.day !== plain.day ||
|
|
147
|
+
roundTrip.hour !== plain.hour ||
|
|
148
|
+
roundTrip.minute !== plain.minute ||
|
|
149
|
+
roundTrip.second !== plain.second
|
|
150
|
+
) {
|
|
151
|
+
throw new NonexistentLocalTimeError(
|
|
152
|
+
`${JSON.stringify(local)} in ${zone} does not exist (DST spring-forward gap).`,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
return msToUtcFields(zoned.epochMilliseconds);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function classifyRejection(local, zone, fold) {
|
|
159
|
+
// Temporal's 'reject' throws for BOTH gap and ambiguity; the Intl
|
|
160
|
+
// prober re-derives which, throwing our typed error (or resolving,
|
|
161
|
+
// if Temporal rejected something the prober can settle).
|
|
162
|
+
return resolveViaIntl(local, zone, fold);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Resolve a naive local civil time + IANA zone to UTC fields.
|
|
167
|
+
* fold: null/undefined (reject ambiguity), 0 (earlier), 1 (later).
|
|
168
|
+
*/
|
|
169
|
+
export function resolveCivilToUtc(local, zone, fold = null) {
|
|
170
|
+
if (typeof globalThis.Temporal !== "undefined") {
|
|
171
|
+
return resolveViaTemporal(local, zone, fold);
|
|
172
|
+
}
|
|
173
|
+
return resolveViaIntl(local, zone, fold);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const RAD_TO_DEG = 180 / Math.PI;
|
|
177
|
+
export function radiansToDegrees(rad) {
|
|
178
|
+
return rad * RAD_TO_DEG;
|
|
179
|
+
}
|
|
180
|
+
export function degreesToRadians(deg) {
|
|
181
|
+
return deg / RAD_TO_DEG;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* The one-call chart surface. Construct once (parses ~13 MB of
|
|
186
|
+
* embedded ephemeris data), then computeChart per birth.
|
|
187
|
+
*/
|
|
188
|
+
export class Ephemeris {
|
|
189
|
+
constructor() {
|
|
190
|
+
this.engine = new wasm.Engine();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Load one extended minor body's vendored table text at runtime. */
|
|
194
|
+
loadMinorBodyTable(name, content) {
|
|
195
|
+
this.engine.loadMinorBodyTable(name, content);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* civil: {year, month, day, hour, minute, second?}; zone: IANA name;
|
|
200
|
+
* observer: {latitudeRad, longitudeRad, heightM?} (radians — use
|
|
201
|
+
* degreesToRadians for degree inputs); options: {houseSystem?,
|
|
202
|
+
* includeMinorBodies?, ayanamsa?, fold?}.
|
|
203
|
+
* Returns the chart object (all angles radians) with utc attached.
|
|
204
|
+
*/
|
|
205
|
+
computeChart(civil, zone, observer, options = {}) {
|
|
206
|
+
const utc = resolveCivilToUtc(civil, zone, options.fold ?? null);
|
|
207
|
+
const chart = this.computeChartUtc(utc, observer, options);
|
|
208
|
+
chart.utc = utc;
|
|
209
|
+
chart.ianaZone = zone;
|
|
210
|
+
return chart;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** Same, from an already-resolved UTC instant. */
|
|
214
|
+
computeChartUtc(utc, observer, options = {}) {
|
|
215
|
+
const request = JSON.stringify({
|
|
216
|
+
utc,
|
|
217
|
+
observer,
|
|
218
|
+
options: {
|
|
219
|
+
houseSystem: options.houseSystem,
|
|
220
|
+
includeMinorBodies: options.includeMinorBodies,
|
|
221
|
+
ayanamsa: options.ayanamsa,
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
return JSON.parse(this.engine.computeChartJson(request));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Positions-only fast path: apparent geocentric longitude/latitude/
|
|
229
|
+
* distance/rate for just the requested bodies (same numbers as the
|
|
230
|
+
* full chart's `bodies`), skipping houses, lunar points, lots,
|
|
231
|
+
* aspects, and patterns. Built for transit scans that sample a few
|
|
232
|
+
* slow bodies across thousands of instants — a one-body query costs
|
|
233
|
+
* a fraction of a full chart. utc: resolved UTC fields; bodies:
|
|
234
|
+
* array of body names (chart bodies and loaded minors).
|
|
235
|
+
*/
|
|
236
|
+
computeBodies(utc, bodies) {
|
|
237
|
+
const request = JSON.stringify({
|
|
238
|
+
utc: { second: 0, ...utc },
|
|
239
|
+
bodies,
|
|
240
|
+
});
|
|
241
|
+
return JSON.parse(this.engine.computeBodiesJson(request));
|
|
242
|
+
}
|
|
243
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aulunarcana/ephemeris",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AuLun Ephemeris: NASA-grade astronomical ephemeris and chart engine (WASM). Free for non-commercial use; commercial licenses available.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/AuLunArcana/ephemeris.git"
|
|
9
|
+
},
|
|
10
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
11
|
+
"main": "index.mjs",
|
|
12
|
+
"types": "index.d.ts",
|
|
13
|
+
"files": ["index.mjs", "index.d.ts", "pkg/", "LICENSE"],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"prepack": "cd .. && wasm-pack build --target nodejs --release --out-dir js/pkg && node -e \"fs.rmSync('js/pkg/.gitignore',{force:true})\"",
|
|
16
|
+
"test": "node test/smoke.mjs"
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=18"
|
|
20
|
+
}
|
|
21
|
+
}
|
package/pkg/LICENSE
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
AuLun Ephemeris — Proprietary License
|
|
2
|
+
Free for Non-Commercial Use
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2026 AuLun Arcana LLC. All rights reserved.
|
|
5
|
+
|
|
6
|
+
This license governs the compiled AuLun Ephemeris package (the
|
|
7
|
+
"Software"): the WASM binary, the JavaScript/TypeScript wrapper, and
|
|
8
|
+
the embedded astronomical data as distributed. Source code is not
|
|
9
|
+
included and is not licensed.
|
|
10
|
+
|
|
11
|
+
1. NON-COMMERCIAL GRANT. You may install and use the Software free of
|
|
12
|
+
charge for personal, educational, research, and other
|
|
13
|
+
non-commercial purposes. "Non-commercial" excludes any use in or
|
|
14
|
+
for a product, service, or activity that is sold, monetized, or
|
|
15
|
+
operated for commercial advantage, whether or not for profit.
|
|
16
|
+
|
|
17
|
+
2. COMMERCIAL USE. Any commercial use requires a separate commercial
|
|
18
|
+
license from the copyright holder. Contact:
|
|
19
|
+
https://github.com/routerbad
|
|
20
|
+
|
|
21
|
+
3. RESTRICTIONS. You may not (a) redistribute, sublicense, sell, or
|
|
22
|
+
host the Software for use by third parties except as an
|
|
23
|
+
incidental, non-separable part of a permitted non-commercial
|
|
24
|
+
application; (b) modify, adapt, or create derivative works of the
|
|
25
|
+
Software; (c) reverse engineer, decompile, or disassemble the
|
|
26
|
+
Software, or extract its embedded implementation, except to the
|
|
27
|
+
extent applicable law expressly permits despite this limitation;
|
|
28
|
+
(d) remove or alter proprietary notices.
|
|
29
|
+
|
|
30
|
+
4. DATA. The astronomical data embedded in the Software derives from
|
|
31
|
+
public-domain and factual sources (documented by the copyright
|
|
32
|
+
holder); nothing in this license restricts your independent use of
|
|
33
|
+
those underlying public sources.
|
|
34
|
+
|
|
35
|
+
5. OWNERSHIP. The Software is licensed, not sold. The copyright
|
|
36
|
+
holder retains all rights not expressly granted.
|
|
37
|
+
|
|
38
|
+
6. TERMINATION. This license terminates automatically if you breach
|
|
39
|
+
it. Upon termination you must cease use and destroy copies.
|
|
40
|
+
|
|
41
|
+
7. NO WARRANTY. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
|
42
|
+
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
43
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, AND
|
|
44
|
+
NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE
|
|
45
|
+
FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM THE USE OF
|
|
46
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
export class Engine {
|
|
5
|
+
free(): void;
|
|
6
|
+
[Symbol.dispose](): void;
|
|
7
|
+
/**
|
|
8
|
+
* Positions-only fast path: apparent geocentric longitude,
|
|
9
|
+
* latitude, distance, and daily rate for a caller-chosen subset
|
|
10
|
+
* of bodies. Same numbers as the full chart's `bodies` (same
|
|
11
|
+
* pipeline), skipping houses/lunar points/lots/aspects/patterns
|
|
12
|
+
* entirely -- built for transit scans that sample one or a few
|
|
13
|
+
* slow bodies across thousands of instants. Input JSON:
|
|
14
|
+
* {"utc": {...}, "bodies": ["jupiter", ...]}.
|
|
15
|
+
*/
|
|
16
|
+
computeBodiesJson(request_json: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Computes a chart from a RESOLVED UTC instant. Input/output are
|
|
19
|
+
* JSON strings (the JS wrapper owns object conversion, degree
|
|
20
|
+
* helpers, and civil-time resolution). All angles radians,
|
|
21
|
+
* tropical true-ecliptic-of-date; sidereal fields additive.
|
|
22
|
+
*/
|
|
23
|
+
computeChartJson(request_json: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Loads one extended minor body's vendored table content
|
|
26
|
+
* (data/minor_bodies/<name>_vectors.txt) at runtime -- the 16
|
|
27
|
+
* extended minors are not embedded. Charts requesting an
|
|
28
|
+
* unloaded minor degrade it into `out_of_range` (M3).
|
|
29
|
+
*/
|
|
30
|
+
loadMinorBodyTable(name: string, content: string): void;
|
|
31
|
+
/**
|
|
32
|
+
* Parses every embedded dataset once (do this at startup, not
|
|
33
|
+
* per chart).
|
|
34
|
+
*/
|
|
35
|
+
constructor();
|
|
36
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/* @ts-self-types="./ephemeris_wasm.d.ts" */
|
|
2
|
+
|
|
3
|
+
class Engine {
|
|
4
|
+
__destroy_into_raw() {
|
|
5
|
+
const ptr = this.__wbg_ptr;
|
|
6
|
+
this.__wbg_ptr = 0;
|
|
7
|
+
EngineFinalization.unregister(this);
|
|
8
|
+
return ptr;
|
|
9
|
+
}
|
|
10
|
+
free() {
|
|
11
|
+
const ptr = this.__destroy_into_raw();
|
|
12
|
+
wasm.__wbg_engine_free(ptr, 0);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Positions-only fast path: apparent geocentric longitude,
|
|
16
|
+
* latitude, distance, and daily rate for a caller-chosen subset
|
|
17
|
+
* of bodies. Same numbers as the full chart's `bodies` (same
|
|
18
|
+
* pipeline), skipping houses/lunar points/lots/aspects/patterns
|
|
19
|
+
* entirely -- built for transit scans that sample one or a few
|
|
20
|
+
* slow bodies across thousands of instants. Input JSON:
|
|
21
|
+
* {"utc": {...}, "bodies": ["jupiter", ...]}.
|
|
22
|
+
* @param {string} request_json
|
|
23
|
+
* @returns {string}
|
|
24
|
+
*/
|
|
25
|
+
computeBodiesJson(request_json) {
|
|
26
|
+
let deferred3_0;
|
|
27
|
+
let deferred3_1;
|
|
28
|
+
try {
|
|
29
|
+
const ptr0 = passStringToWasm0(request_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
30
|
+
const len0 = WASM_VECTOR_LEN;
|
|
31
|
+
const ret = wasm.engine_computeBodiesJson(this.__wbg_ptr, ptr0, len0);
|
|
32
|
+
var ptr2 = ret[0];
|
|
33
|
+
var len2 = ret[1];
|
|
34
|
+
if (ret[3]) {
|
|
35
|
+
ptr2 = 0; len2 = 0;
|
|
36
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
37
|
+
}
|
|
38
|
+
deferred3_0 = ptr2;
|
|
39
|
+
deferred3_1 = len2;
|
|
40
|
+
return getStringFromWasm0(ptr2, len2);
|
|
41
|
+
} finally {
|
|
42
|
+
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Computes a chart from a RESOLVED UTC instant. Input/output are
|
|
47
|
+
* JSON strings (the JS wrapper owns object conversion, degree
|
|
48
|
+
* helpers, and civil-time resolution). All angles radians,
|
|
49
|
+
* tropical true-ecliptic-of-date; sidereal fields additive.
|
|
50
|
+
* @param {string} request_json
|
|
51
|
+
* @returns {string}
|
|
52
|
+
*/
|
|
53
|
+
computeChartJson(request_json) {
|
|
54
|
+
let deferred3_0;
|
|
55
|
+
let deferred3_1;
|
|
56
|
+
try {
|
|
57
|
+
const ptr0 = passStringToWasm0(request_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
58
|
+
const len0 = WASM_VECTOR_LEN;
|
|
59
|
+
const ret = wasm.engine_computeChartJson(this.__wbg_ptr, ptr0, len0);
|
|
60
|
+
var ptr2 = ret[0];
|
|
61
|
+
var len2 = ret[1];
|
|
62
|
+
if (ret[3]) {
|
|
63
|
+
ptr2 = 0; len2 = 0;
|
|
64
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
65
|
+
}
|
|
66
|
+
deferred3_0 = ptr2;
|
|
67
|
+
deferred3_1 = len2;
|
|
68
|
+
return getStringFromWasm0(ptr2, len2);
|
|
69
|
+
} finally {
|
|
70
|
+
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Loads one extended minor body's vendored table content
|
|
75
|
+
* (data/minor_bodies/<name>_vectors.txt) at runtime -- the 16
|
|
76
|
+
* extended minors are not embedded. Charts requesting an
|
|
77
|
+
* unloaded minor degrade it into `out_of_range` (M3).
|
|
78
|
+
* @param {string} name
|
|
79
|
+
* @param {string} content
|
|
80
|
+
*/
|
|
81
|
+
loadMinorBodyTable(name, content) {
|
|
82
|
+
const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
83
|
+
const len0 = WASM_VECTOR_LEN;
|
|
84
|
+
const ptr1 = passStringToWasm0(content, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
85
|
+
const len1 = WASM_VECTOR_LEN;
|
|
86
|
+
const ret = wasm.engine_loadMinorBodyTable(this.__wbg_ptr, ptr0, len0, ptr1, len1);
|
|
87
|
+
if (ret[1]) {
|
|
88
|
+
throw takeFromExternrefTable0(ret[0]);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Parses every embedded dataset once (do this at startup, not
|
|
93
|
+
* per chart).
|
|
94
|
+
*/
|
|
95
|
+
constructor() {
|
|
96
|
+
const ret = wasm.engine_new();
|
|
97
|
+
if (ret[2]) {
|
|
98
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
99
|
+
}
|
|
100
|
+
this.__wbg_ptr = ret[0];
|
|
101
|
+
EngineFinalization.register(this, this.__wbg_ptr, this);
|
|
102
|
+
return this;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (Symbol.dispose) Engine.prototype[Symbol.dispose] = Engine.prototype.free;
|
|
106
|
+
exports.Engine = Engine;
|
|
107
|
+
function __wbg_get_imports() {
|
|
108
|
+
const import0 = {
|
|
109
|
+
__proto__: null,
|
|
110
|
+
__wbg_Error_92b29b0548f8b746: function(arg0, arg1) {
|
|
111
|
+
const ret = Error(getStringFromWasm0(arg0, arg1));
|
|
112
|
+
return ret;
|
|
113
|
+
},
|
|
114
|
+
__wbg___wbindgen_throw_344f42d3211c4765: function(arg0, arg1) {
|
|
115
|
+
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
116
|
+
},
|
|
117
|
+
__wbindgen_init_externref_table: function() {
|
|
118
|
+
const table = wasm.__wbindgen_externrefs;
|
|
119
|
+
const offset = table.grow(4);
|
|
120
|
+
table.set(0, undefined);
|
|
121
|
+
table.set(offset + 0, undefined);
|
|
122
|
+
table.set(offset + 1, null);
|
|
123
|
+
table.set(offset + 2, true);
|
|
124
|
+
table.set(offset + 3, false);
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
return {
|
|
128
|
+
__proto__: null,
|
|
129
|
+
"./ephemeris_wasm_bg.js": import0,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const EngineFinalization = (typeof FinalizationRegistry === 'undefined')
|
|
134
|
+
? { register: () => {}, unregister: () => {} }
|
|
135
|
+
: new FinalizationRegistry(ptr => wasm.__wbg_engine_free(ptr, 1));
|
|
136
|
+
|
|
137
|
+
function getStringFromWasm0(ptr, len) {
|
|
138
|
+
return decodeText(ptr >>> 0, len);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let cachedUint8ArrayMemory0 = null;
|
|
142
|
+
function getUint8ArrayMemory0() {
|
|
143
|
+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
|
144
|
+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
|
145
|
+
}
|
|
146
|
+
return cachedUint8ArrayMemory0;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function passStringToWasm0(arg, malloc, realloc) {
|
|
150
|
+
if (realloc === undefined) {
|
|
151
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
152
|
+
const ptr = malloc(buf.length, 1) >>> 0;
|
|
153
|
+
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
|
|
154
|
+
WASM_VECTOR_LEN = buf.length;
|
|
155
|
+
return ptr;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
let len = arg.length;
|
|
159
|
+
let ptr = malloc(len, 1) >>> 0;
|
|
160
|
+
|
|
161
|
+
const mem = getUint8ArrayMemory0();
|
|
162
|
+
|
|
163
|
+
let offset = 0;
|
|
164
|
+
|
|
165
|
+
for (; offset < len; offset++) {
|
|
166
|
+
const code = arg.charCodeAt(offset);
|
|
167
|
+
if (code > 0x7F) break;
|
|
168
|
+
mem[ptr + offset] = code;
|
|
169
|
+
}
|
|
170
|
+
if (offset !== len) {
|
|
171
|
+
if (offset !== 0) {
|
|
172
|
+
arg = arg.slice(offset);
|
|
173
|
+
}
|
|
174
|
+
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
|
175
|
+
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
|
176
|
+
const ret = cachedTextEncoder.encodeInto(arg, view);
|
|
177
|
+
|
|
178
|
+
offset += ret.written;
|
|
179
|
+
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
WASM_VECTOR_LEN = offset;
|
|
183
|
+
return ptr;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function takeFromExternrefTable0(idx) {
|
|
187
|
+
const value = wasm.__wbindgen_externrefs.get(idx);
|
|
188
|
+
wasm.__externref_table_dealloc(idx);
|
|
189
|
+
return value;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
193
|
+
cachedTextDecoder.decode();
|
|
194
|
+
function decodeText(ptr, len) {
|
|
195
|
+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const cachedTextEncoder = new TextEncoder();
|
|
199
|
+
|
|
200
|
+
if (!('encodeInto' in cachedTextEncoder)) {
|
|
201
|
+
cachedTextEncoder.encodeInto = function (arg, view) {
|
|
202
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
203
|
+
view.set(buf);
|
|
204
|
+
return {
|
|
205
|
+
read: arg.length,
|
|
206
|
+
written: buf.length
|
|
207
|
+
};
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let WASM_VECTOR_LEN = 0;
|
|
212
|
+
|
|
213
|
+
const wasmPath = `${__dirname}/ephemeris_wasm_bg.wasm`;
|
|
214
|
+
const wasmBytes = require('fs').readFileSync(wasmPath);
|
|
215
|
+
const wasmModule = new WebAssembly.Module(wasmBytes);
|
|
216
|
+
let wasmInstance = new WebAssembly.Instance(wasmModule, __wbg_get_imports());
|
|
217
|
+
let wasm = wasmInstance.exports;
|
|
218
|
+
wasm.__wbindgen_start();
|
|
Binary file
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const __wbg_engine_free: (a: number, b: number) => void;
|
|
5
|
+
export const engine_computeBodiesJson: (a: number, b: number, c: number) => [number, number, number, number];
|
|
6
|
+
export const engine_computeChartJson: (a: number, b: number, c: number) => [number, number, number, number];
|
|
7
|
+
export const engine_loadMinorBodyTable: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
8
|
+
export const engine_new: () => [number, number, number];
|
|
9
|
+
export const __wbindgen_externrefs: WebAssembly.Table;
|
|
10
|
+
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
11
|
+
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
12
|
+
export const __externref_table_dealloc: (a: number) => void;
|
|
13
|
+
export const __wbindgen_free: (a: number, b: number, c: number) => void;
|
|
14
|
+
export const __wbindgen_start: () => void;
|
package/pkg/package.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ephemeris-wasm",
|
|
3
|
+
"description": "WASM bindings for the ephemeris engine",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
6
|
+
"files": [
|
|
7
|
+
"ephemeris_wasm_bg.wasm",
|
|
8
|
+
"ephemeris_wasm.js",
|
|
9
|
+
"ephemeris_wasm.d.ts"
|
|
10
|
+
],
|
|
11
|
+
"main": "ephemeris_wasm.js",
|
|
12
|
+
"types": "ephemeris_wasm.d.ts"
|
|
13
|
+
}
|