klio 1.4.9 → 1.5.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.
@@ -0,0 +1,369 @@
1
+ // WebContainer-compatible Astrology Service
2
+ // This provides real astrological calculations without native dependencies
3
+
4
+ const { planets, signs } = require('./astrologyConstants');
5
+
6
+ // Pure JavaScript implementation of basic astrological calculations
7
+ class AstrologyServiceWeb {
8
+ constructor() {
9
+ // Current date for calculations
10
+ this.now = new Date();
11
+ }
12
+
13
+ // Calculate Julian Day Number (simplified version)
14
+ calculateJulianDay(date = null) {
15
+ const d = date || this.now;
16
+ const year = d.getFullYear();
17
+ const month = d.getMonth() + 1;
18
+ const day = d.getDate();
19
+ const hour = d.getHours();
20
+ const minute = d.getMinutes();
21
+
22
+ // Simplified Julian Day calculation (not astronomically precise but works for demo)
23
+ const a = Math.floor((14 - month) / 12);
24
+ const y = year + 4800 - a;
25
+ const m = month + 12 * a - 3;
26
+
27
+ const jdn = day + Math.floor((153 * m + 2) / 5) + 365 * y + Math.floor(y / 4) - Math.floor(y / 100) + Math.floor(y / 400) - 32045;
28
+
29
+ // Add time of day
30
+ const timeFraction = (hour - 12) / 24 + minute / 1440;
31
+
32
+ return jdn + timeFraction;
33
+ }
34
+
35
+ // Calculate mean planet positions (simplified ephemeris)
36
+ // Note: This is a simplified model, not astronomically precise
37
+ calculateMeanPlanetPosition(planetName, julianDay) {
38
+ const planet = planetName.toLowerCase();
39
+
40
+ // Base positions (epoch 2000.0)
41
+ const epochPositions = {
42
+ sun: { longitude: 280.460, dailyMotion: 0.985647 },
43
+ moon: { longitude: 318.351, dailyMotion: 13.176396 },
44
+ mercury: { longitude: 252.251, dailyMotion: 4.092334 },
45
+ venus: { longitude: 181.979, dailyMotion: 1.602130 },
46
+ mars: { longitude: 355.433, dailyMotion: 0.524020 },
47
+ jupiter: { longitude: 34.353, dailyMotion: 0.083085 },
48
+ saturn: { longitude: 50.077, dailyMotion: 0.033449 },
49
+ uranus: { longitude: 314.328, dailyMotion: 0.011725 },
50
+ neptune: { longitude: 304.348, dailyMotion: 0.005981 },
51
+ pluto: { longitude: 238.950, dailyMotion: 0.003967 }
52
+ };
53
+
54
+ if (!epochPositions[planet]) {
55
+ throw new Error("Unknown planet: " + planet);
56
+ }
57
+
58
+ // Days since epoch (simplified)
59
+ const daysSinceEpoch = julianDay - 2451545; // 2000.0 epoch
60
+
61
+ // Calculate mean longitude
62
+ let longitude = epochPositions[planet].longitude + epochPositions[planet].dailyMotion * daysSinceEpoch;
63
+
64
+ // Normalize to 0-360 range
65
+ longitude = longitude % 360;
66
+ if (longitude < 0) longitude += 360;
67
+
68
+ return longitude;
69
+ }
70
+
71
+ // Convert longitude to sign and degree
72
+ longitudeToSignDegree(longitude) {
73
+ // Normalize longitude
74
+ longitude = longitude % 360;
75
+ if (longitude < 0) longitude += 360;
76
+
77
+ // Calculate sign (0-11)
78
+ const signIndex = Math.floor(longitude / 30);
79
+ const sign = signs[signIndex];
80
+
81
+ // Calculate degree within sign
82
+ const degree = longitude % 30;
83
+
84
+ return { sign, degree };
85
+ }
86
+
87
+ // Get astrological data for a planet
88
+ getAstrologicalData(planetName, date = null) {
89
+ const planet = planetName.toLowerCase();
90
+
91
+ if (!planets[planet]) {
92
+ throw new Error("Unknown planet: " + planet);
93
+ }
94
+
95
+ // Calculate Julian Day
96
+ const julianDay = this.calculateJulianDay(date);
97
+
98
+ // Calculate planet position
99
+ const longitude = this.calculateMeanPlanetPosition(planet, julianDay);
100
+ const { sign, degree } = this.longitudeToSignDegree(longitude);
101
+
102
+ // Determine dignity (simplified)
103
+ const dignity = this._getDignity(planet, sign);
104
+
105
+ // Determine element
106
+ const element = this._getElement(sign);
107
+
108
+ // Determine decan
109
+ const decan = this._getDecan(sign, degree);
110
+
111
+ return {
112
+ planet: planetName,
113
+ sign,
114
+ degreeInSign: degree.toFixed(1),
115
+ dignity,
116
+ element,
117
+ decan,
118
+ longitude: longitude.toFixed(2)
119
+ };
120
+ }
121
+
122
+ // Get dignity for planet in sign
123
+ _getDignity(planet, sign) {
124
+ // Essential dignities (simplified)
125
+ const rulerships = {
126
+ sun: 'Leo',
127
+ moon: 'Cancer',
128
+ mercury: ['Gemini', 'Virgo'],
129
+ venus: ['Taurus', 'Libra'],
130
+ mars: ['Aries', 'Scorpio'],
131
+ jupiter: ['Sagittarius', 'Pisces'],
132
+ saturn: ['Capricorn', 'Aquarius'],
133
+ uranus: 'Aquarius',
134
+ neptune: 'Pisces',
135
+ pluto: 'Scorpio'
136
+ };
137
+
138
+ const exaltations = {
139
+ sun: 'Aries',
140
+ moon: 'Taurus',
141
+ mercury: 'Virgo',
142
+ venus: 'Pisces',
143
+ mars: 'Capricorn',
144
+ jupiter: 'Cancer',
145
+ saturn: 'Libra'
146
+ };
147
+
148
+ const detriments = {
149
+ sun: 'Aquarius',
150
+ moon: 'Capricorn',
151
+ mercury: ['Sagittarius', 'Pisces'],
152
+ venus: ['Aries', 'Scorpio'],
153
+ mars: ['Taurus', 'Libra'],
154
+ jupiter: ['Gemini', 'Virgo'],
155
+ saturn: ['Cancer', 'Leo']
156
+ };
157
+
158
+ const falls = {
159
+ sun: 'Libra',
160
+ moon: 'Scorpio',
161
+ mercury: 'Pisces',
162
+ venus: 'Virgo',
163
+ mars: 'Cancer',
164
+ jupiter: 'Capricorn',
165
+ saturn: 'Aries'
166
+ };
167
+
168
+ // Check rulership
169
+ if (Array.isArray(rulerships[planet])) {
170
+ if (rulerships[planet].includes(sign)) {
171
+ return 'Rulership';
172
+ }
173
+ } else if (rulerships[planet] === sign) {
174
+ return 'Rulership';
175
+ }
176
+
177
+ // Check exaltation
178
+ if (exaltations[planet] === sign) {
179
+ return 'Exaltation';
180
+ }
181
+
182
+ // Check detriment
183
+ if (Array.isArray(detriments[planet])) {
184
+ if (detriments[planet].includes(sign)) {
185
+ return 'Detriment';
186
+ }
187
+ } else if (detriments[planet] === sign) {
188
+ return 'Detriment';
189
+ }
190
+
191
+ // Check fall
192
+ if (falls[planet] === sign) {
193
+ return 'Fall';
194
+ }
195
+
196
+ return 'Neutral';
197
+ }
198
+
199
+ // Get element for sign
200
+ _getElement(sign) {
201
+ const fireSigns = ['Aries', 'Leo', 'Sagittarius'];
202
+ const earthSigns = ['Taurus', 'Virgo', 'Capricorn'];
203
+ const airSigns = ['Gemini', 'Libra', 'Aquarius'];
204
+ const waterSigns = ['Cancer', 'Scorpio', 'Pisces'];
205
+
206
+ if (fireSigns.includes(sign)) return 'Fire';
207
+ if (earthSigns.includes(sign)) return 'Earth';
208
+ if (airSigns.includes(sign)) return 'Air';
209
+ if (waterSigns.includes(sign)) return 'Water';
210
+
211
+ return 'Unknown';
212
+ }
213
+
214
+ // Get decan for sign and degree
215
+ _getDecan(sign, degree) {
216
+ return Math.floor(degree / 10) + 1;
217
+ }
218
+
219
+ // Get critical planets (planets at critical degrees)
220
+ getCriticalPlanets(date = null) {
221
+ const criticalPlanets = [];
222
+ const criticalDegrees = [0, 15, 19, 29]; // Anaretic, midpoint, Via Combusta
223
+
224
+ for (const [planetName, planetId] of Object.entries(planets)) {
225
+ const data = this.getAstrologicalData(planetName, date);
226
+ const degree = parseFloat(data.degreeInSign);
227
+
228
+ // Check if degree is critical (within 1 degree orb)
229
+ for (const criticalDegree of criticalDegrees) {
230
+ if (Math.abs(degree - criticalDegree) < 1) {
231
+ let criticalType;
232
+ let interpretation;
233
+
234
+ switch (criticalDegree) {
235
+ case 0:
236
+ case 29:
237
+ criticalType = 'Anaretic Degree';
238
+ interpretation = 'Critical transition point - decisions and endings';
239
+ break;
240
+ case 15:
241
+ criticalType = 'Midpoint';
242
+ interpretation = 'Balanced energy - harmony and integration';
243
+ break;
244
+ case 19:
245
+ criticalType = 'Via Combusta';
246
+ interpretation = 'Challenging degree - intensity and transformation';
247
+ break;
248
+ }
249
+
250
+ criticalPlanets.push({
251
+ name: planetName,
252
+ sign: data.sign,
253
+ degree: data.degreeInSign,
254
+ criticalType,
255
+ interpretation
256
+ });
257
+ break; // Only add once per planet
258
+ }
259
+ }
260
+ }
261
+
262
+ return criticalPlanets;
263
+ }
264
+
265
+ // Get retrograde planets (simplified - uses fixed dates for demo)
266
+ getRetrogradePlanets(date = null) {
267
+ const d = date || this.now;
268
+ const year = d.getFullYear();
269
+ const month = d.getMonth() + 1;
270
+ const day = d.getDate();
271
+
272
+ // Simplified retrograde periods (not astronomically precise)
273
+ const retrogradePeriods = {
274
+ mercury: [
275
+ { start: { month: 2, day: 16 }, end: { month: 3, day: 9 } },
276
+ { start: { month: 6, day: 18 }, end: { month: 7, day: 12 } },
277
+ { start: { month: 10, day: 21 }, end: { month: 11, day: 10 } }
278
+ ],
279
+ venus: [
280
+ { start: { month: 12, day: 19 }, end: { month: 1, day: 29 } }
281
+ ],
282
+ mars: [
283
+ { start: { month: 10, day: 30 }, end: { month: 1, day: 12 } }
284
+ ],
285
+ jupiter: [
286
+ { start: { month: 7, day: 28 }, end: { month: 11, day: 23 } }
287
+ ],
288
+ saturn: [
289
+ { start: { month: 6, day: 17 }, end: { month: 11, day: 4 } }
290
+ ],
291
+ uranus: [
292
+ { start: { month: 8, day: 24 }, end: { month: 1, day: 22 } }
293
+ ],
294
+ neptune: [
295
+ { start: { month: 6, day: 25 }, end: { month: 12, day: 1 } }
296
+ ],
297
+ pluto: [
298
+ { start: { month: 4, day: 27 }, end: { month: 10, day: 6 } }
299
+ ]
300
+ };
301
+
302
+ const retrogradePlanets = [];
303
+
304
+ for (const [planet, periods] of Object.entries(retrogradePeriods)) {
305
+ for (const period of periods) {
306
+ // Check if current date is within retrograde period
307
+ const startDate = new Date(year, period.start.month - 1, period.start.day);
308
+ const endDate = new Date(year, period.end.month - 1, period.end.day);
309
+
310
+ // Handle year wrap-around
311
+ if (period.end.month < period.start.month) {
312
+ if (month > period.start.month || month < period.end.month) {
313
+ retrogradePlanets.push({
314
+ name: planet,
315
+ status: 'retrograde'
316
+ });
317
+ break;
318
+ }
319
+ } else if (d >= startDate && d <= endDate) {
320
+ retrogradePlanets.push({
321
+ name: planet,
322
+ status: 'retrograde'
323
+ });
324
+ break;
325
+ }
326
+ }
327
+ }
328
+
329
+ // Add stationary points (when planets change direction)
330
+ // For simplicity, we'll add a few stationary planets
331
+ if (month === 3 && day >= 8 && day <= 10) {
332
+ retrogradePlanets.push({ name: 'mercury', status: 'stationary' });
333
+ }
334
+ if (month === 7 && day >= 11 && day <= 13) {
335
+ retrogradePlanets.push({ name: 'mercury', status: 'stationary' });
336
+ }
337
+
338
+ return retrogradePlanets;
339
+ }
340
+
341
+ // Analyze element distribution
342
+ analyzeElementDistribution(date = null, useBirthData = false) {
343
+ const elementCounts = { Fire: 0, Earth: 0, Air: 0, Water: 0 };
344
+
345
+ for (const [planetName] of Object.entries(planets)) {
346
+ const data = this.getAstrologicalData(planetName, date);
347
+ const element = data.element;
348
+
349
+ if (elementCounts[element] !== undefined) {
350
+ elementCounts[element]++;
351
+ }
352
+ }
353
+
354
+ return { elementCounts };
355
+ }
356
+
357
+ // Get all planet positions
358
+ getAllPlanetPositions(date = null) {
359
+ const positions = {};
360
+
361
+ for (const [planetName] of Object.entries(planets)) {
362
+ positions[planetName] = this.getAstrologicalData(planetName, date);
363
+ }
364
+
365
+ return positions;
366
+ }
367
+ }
368
+
369
+ module.exports = new AstrologyServiceWeb();
@@ -0,0 +1,106 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const vm = require('vm');
4
+
5
+ let modulePromise = null;
6
+
7
+ function ensureFileExists(filePath) {
8
+ if (!fs.existsSync(filePath)) {
9
+ throw new Error(`Sweph WASM asset not found: ${filePath}`);
10
+ }
11
+ }
12
+
13
+ function ensureFileSize(filePath, minimumBytes) {
14
+ const stat = fs.statSync(filePath);
15
+ if (!stat || stat.size < minimumBytes) {
16
+ throw new Error(`Sweph WASM asset too small (${stat ? stat.size : 0} bytes): ${filePath}`);
17
+ }
18
+ }
19
+
20
+ function resolveSwephBaseDir() {
21
+ const candidates = [
22
+ path.resolve(__dirname, '..', 'gui', 'public', 'sweph'),
23
+ path.resolve(process.cwd(), 'src', 'gui', 'public', 'sweph'),
24
+ '/src/gui/public/sweph'
25
+ ];
26
+
27
+ for (const candidate of candidates) {
28
+ if (fs.existsSync(candidate)) {
29
+ return candidate;
30
+ }
31
+ }
32
+
33
+ return candidates[0];
34
+ }
35
+
36
+ function createSandbox(moduleConfig) {
37
+ const atobFallback = (value) => Buffer.from(value, 'base64').toString('binary');
38
+ const btoaFallback = (value) => Buffer.from(value, 'binary').toString('base64');
39
+
40
+ const sandbox = {
41
+ Module: moduleConfig,
42
+ require,
43
+ process,
44
+ console,
45
+ Buffer,
46
+ setTimeout,
47
+ clearTimeout,
48
+ setInterval,
49
+ clearInterval,
50
+ TextDecoder,
51
+ TextEncoder,
52
+ URL,
53
+ atob: globalThis.atob || atobFallback,
54
+ btoa: globalThis.btoa || btoaFallback
55
+ };
56
+
57
+ sandbox.globalThis = sandbox;
58
+ return sandbox;
59
+ }
60
+
61
+ function loadSwephWasmModule() {
62
+ if (modulePromise) {
63
+ return modulePromise;
64
+ }
65
+
66
+ modulePromise = new Promise((resolve, reject) => {
67
+ const baseDir = resolveSwephBaseDir();
68
+ const astroJsPath = path.join(baseDir, 'astro.js');
69
+ const wasmPath = path.join(baseDir, 'astro.wasm');
70
+ const dataPath = path.join(baseDir, 'astro.data');
71
+
72
+ try {
73
+ ensureFileExists(astroJsPath);
74
+ ensureFileExists(wasmPath);
75
+ ensureFileExists(dataPath);
76
+ ensureFileSize(wasmPath, 500000);
77
+ ensureFileSize(dataPath, 500000);
78
+ } catch (error) {
79
+ reject(error);
80
+ return;
81
+ }
82
+
83
+ const moduleConfig = {
84
+ locateFile: (filename) => path.join(baseDir, filename),
85
+ print: () => {},
86
+ printErr: () => {},
87
+ onRuntimeInitialized: () => resolve(moduleConfig),
88
+ onAbort: (reason) => reject(new Error(reason || 'Sweph WASM aborted'))
89
+ };
90
+
91
+ const sandbox = createSandbox(moduleConfig);
92
+
93
+ try {
94
+ const code = fs.readFileSync(astroJsPath, 'utf8');
95
+ vm.runInNewContext(code, sandbox, { filename: astroJsPath });
96
+ } catch (error) {
97
+ reject(error);
98
+ }
99
+ });
100
+
101
+ return modulePromise;
102
+ }
103
+
104
+ module.exports = {
105
+ loadSwephWasmModule
106
+ };