mysticapi 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/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/README.md +160 -0
- package/dist/index.d.mts +265 -0
- package/dist/index.d.ts +265 -0
- package/dist/index.js +270 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +247 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +74 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the MysticAPI HTTP contract.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors https://mysticapi.com/.well-known/openapi.json (OpenAPI 3.1). The live
|
|
5
|
+
* spec is the source of truth; these types track it and are kept deliberately
|
|
6
|
+
* permissive (index signatures on open-ended objects) so the client never breaks
|
|
7
|
+
* when the engine adds fields.
|
|
8
|
+
*/
|
|
9
|
+
/** A birth instant expressed in UTC. Convert local time + timezone to UTC first. */
|
|
10
|
+
interface BirthInput {
|
|
11
|
+
/** Full year, 1–2200. */
|
|
12
|
+
year: number;
|
|
13
|
+
/** Month, 1–12. */
|
|
14
|
+
month: number;
|
|
15
|
+
/** Day of month, 1–31. */
|
|
16
|
+
day: number;
|
|
17
|
+
/** Hour, 0–23 (UTC). */
|
|
18
|
+
hour: number;
|
|
19
|
+
/** Minute, 0–59 (UTC). */
|
|
20
|
+
minute: number;
|
|
21
|
+
/** Second, 0–59 (UTC). Defaults to 0. */
|
|
22
|
+
second?: number;
|
|
23
|
+
}
|
|
24
|
+
/** A zodiac placement: sign name plus degree within the sign. */
|
|
25
|
+
interface ZodiacPlacement {
|
|
26
|
+
sign: string;
|
|
27
|
+
degree: number;
|
|
28
|
+
}
|
|
29
|
+
/** An Energy Blueprint gate/line placement on the 64-gate wheel. */
|
|
30
|
+
interface GatePlacement {
|
|
31
|
+
/** Gate number, 1–64. */
|
|
32
|
+
gate: number;
|
|
33
|
+
/** Line number, 1–6. */
|
|
34
|
+
line: number;
|
|
35
|
+
}
|
|
36
|
+
/** Geocentric position of a single celestial body. */
|
|
37
|
+
interface BodyPosition {
|
|
38
|
+
label?: string;
|
|
39
|
+
/** Ecliptic longitude in degrees, 0 ≤ longitude < 360. */
|
|
40
|
+
longitude?: number;
|
|
41
|
+
zodiac?: ZodiacPlacement;
|
|
42
|
+
gate?: GatePlacement;
|
|
43
|
+
retrograde?: boolean;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
}
|
|
46
|
+
/** A forthcoming sky event (retrograde station or new/full moon). May be null. */
|
|
47
|
+
interface SkyEvent {
|
|
48
|
+
date?: string;
|
|
49
|
+
type?: 'retrograde_start' | 'retrograde_end' | 'new_moon' | 'full_moon';
|
|
50
|
+
planet?: string;
|
|
51
|
+
title?: string;
|
|
52
|
+
/** Practical prep guidance for the event. */
|
|
53
|
+
prep?: string;
|
|
54
|
+
daysAway?: number;
|
|
55
|
+
[key: string]: unknown;
|
|
56
|
+
}
|
|
57
|
+
/** Moon phase snapshot for {@link SkyToday}. */
|
|
58
|
+
interface MoonState {
|
|
59
|
+
phaseName?: string;
|
|
60
|
+
/** Illuminated fraction, 0–1. */
|
|
61
|
+
illumination?: number;
|
|
62
|
+
elongationDeg?: number;
|
|
63
|
+
nextNewMoon?: SkyEvent | null;
|
|
64
|
+
nextFullMoon?: SkyEvent | null;
|
|
65
|
+
[key: string]: unknown;
|
|
66
|
+
}
|
|
67
|
+
/** Active + upcoming retrograde state for {@link SkyToday}. */
|
|
68
|
+
interface RetrogradeState {
|
|
69
|
+
active?: Array<{
|
|
70
|
+
planet?: string;
|
|
71
|
+
label?: string;
|
|
72
|
+
}>;
|
|
73
|
+
upcomingStations?: SkyEvent[];
|
|
74
|
+
[key: string]: unknown;
|
|
75
|
+
}
|
|
76
|
+
/** Response of {@link MysticApi.skyToday}: the universal (non-personal) sky. */
|
|
77
|
+
interface SkyToday {
|
|
78
|
+
date: string;
|
|
79
|
+
generatedAt?: string;
|
|
80
|
+
moon: MoonState;
|
|
81
|
+
retrogrades: RetrogradeState;
|
|
82
|
+
/** Positions keyed by body id (e.g. `sun`, `moon`, `mercury`, ...). */
|
|
83
|
+
positions: Record<string, BodyPosition>;
|
|
84
|
+
upcoming: SkyEvent[];
|
|
85
|
+
attribution?: string;
|
|
86
|
+
[key: string]: unknown;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The computed Energy Blueprint chart. The engine returns a rich, evolving
|
|
90
|
+
* object (birth with jdn, the 88°-solar-arc design moment, per-body conscious +
|
|
91
|
+
* unconscious gate maps, and the derived chart: type, authority, strategy,
|
|
92
|
+
* profile, definition, incarnation cross, channels, centers). Known top-level
|
|
93
|
+
* fields are typed; the index signature keeps forward-compatibility.
|
|
94
|
+
*/
|
|
95
|
+
interface BodygraphChart {
|
|
96
|
+
birth?: Record<string, unknown>;
|
|
97
|
+
design?: Record<string, unknown>;
|
|
98
|
+
personalityGates?: Record<string, GatePlacement>;
|
|
99
|
+
designGates?: Record<string, GatePlacement>;
|
|
100
|
+
chart?: {
|
|
101
|
+
type?: string;
|
|
102
|
+
authority?: string;
|
|
103
|
+
strategy?: string;
|
|
104
|
+
profile?: string;
|
|
105
|
+
definition?: string;
|
|
106
|
+
cross?: string;
|
|
107
|
+
channels?: unknown;
|
|
108
|
+
centers?: unknown;
|
|
109
|
+
[key: string]: unknown;
|
|
110
|
+
};
|
|
111
|
+
[key: string]: unknown;
|
|
112
|
+
}
|
|
113
|
+
/** Response of {@link MysticApi.bodygraph}: chart JSON plus a rendered SVG. */
|
|
114
|
+
interface BodygraphResult {
|
|
115
|
+
chart: BodygraphChart;
|
|
116
|
+
/** Body-graph SVG markup (a complete `<svg>…</svg>` string). */
|
|
117
|
+
svg: string;
|
|
118
|
+
attribution?: string;
|
|
119
|
+
}
|
|
120
|
+
/** Response of {@link MysticApi.getFreeKey}. The key itself arrives by email. */
|
|
121
|
+
interface FreeKeyResponse {
|
|
122
|
+
message?: string;
|
|
123
|
+
docs?: string;
|
|
124
|
+
[key: string]: unknown;
|
|
125
|
+
}
|
|
126
|
+
/** Options for {@link MysticApi.skyPersonal}. */
|
|
127
|
+
interface SkyPersonalOptions {
|
|
128
|
+
/** When `false`, request a static (non-animated) SVG. Defaults to the API default. */
|
|
129
|
+
animate?: boolean;
|
|
130
|
+
}
|
|
131
|
+
/** The JSON error envelope returned by MysticAPI on non-2xx responses. */
|
|
132
|
+
interface ApiErrorBody {
|
|
133
|
+
error?: string;
|
|
134
|
+
message?: string;
|
|
135
|
+
docs?: string;
|
|
136
|
+
[key: string]: unknown;
|
|
137
|
+
}
|
|
138
|
+
/** Constructor options for {@link MysticApi}. */
|
|
139
|
+
interface MysticApiOptions {
|
|
140
|
+
/** Your API key, e.g. `mk_live_...`. Get a free one via {@link MysticApi.getFreeKey}. */
|
|
141
|
+
apiKey: string;
|
|
142
|
+
/** Override the API base URL. Defaults to `https://mysticapi.com`. */
|
|
143
|
+
baseUrl?: string;
|
|
144
|
+
/** Inject a fetch implementation. Defaults to the runtime's global `fetch`. */
|
|
145
|
+
fetch?: typeof globalThis.fetch;
|
|
146
|
+
}
|
|
147
|
+
/** Options for the keyless helpers ({@link MysticApi.getFreeKey}). */
|
|
148
|
+
interface KeylessOptions {
|
|
149
|
+
/** Override the API base URL. Defaults to `https://mysticapi.com`. */
|
|
150
|
+
baseUrl?: string;
|
|
151
|
+
/** Inject a fetch implementation. Defaults to the runtime's global `fetch`. */
|
|
152
|
+
fetch?: typeof globalThis.fetch;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Default MysticAPI base URL. */
|
|
156
|
+
declare const DEFAULT_BASE_URL = "https://mysticapi.com";
|
|
157
|
+
/**
|
|
158
|
+
* Isomorphic MysticAPI client. Zero dependencies — uses the runtime's global
|
|
159
|
+
* `fetch`, so it runs unchanged on Node 18+, Bun, browsers, and Cloudflare
|
|
160
|
+
* Workers.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```ts
|
|
164
|
+
* const mystic = new MysticApi({ apiKey: 'mk_live_...' });
|
|
165
|
+
* const sky = await mystic.skyToday();
|
|
166
|
+
* console.log(sky.moon.phaseName);
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
declare class MysticApi {
|
|
170
|
+
private readonly apiKey;
|
|
171
|
+
private readonly baseUrl;
|
|
172
|
+
private readonly fetchImpl;
|
|
173
|
+
constructor(options: MysticApiOptions);
|
|
174
|
+
private authHeaders;
|
|
175
|
+
/**
|
|
176
|
+
* Today's universal sky: active retrogrades, moon phase + illumination,
|
|
177
|
+
* geocentric positions for 13 bodies (zodiac + Energy Blueprint gate/line),
|
|
178
|
+
* and a 30-day forward scan of retrograde stations and new/full moons.
|
|
179
|
+
*
|
|
180
|
+
* `GET /v1/sky/today` — metered (1 call).
|
|
181
|
+
*/
|
|
182
|
+
skyToday(): Promise<SkyToday>;
|
|
183
|
+
/**
|
|
184
|
+
* Compute an Energy Blueprint (Human Design) chart from a birth instant and
|
|
185
|
+
* return the full chart JSON plus a rendered body-graph SVG. Location is not
|
|
186
|
+
* required — the body-graph is location-independent.
|
|
187
|
+
*
|
|
188
|
+
* `POST /v1/bodygraph` — metered (1 call).
|
|
189
|
+
*/
|
|
190
|
+
bodygraph(birth: BirthInput): Promise<BodygraphResult>;
|
|
191
|
+
/**
|
|
192
|
+
* Render a personal-sky chart from a birth instant. Returns the SVG markup as
|
|
193
|
+
* a string (`image/svg+xml`). Deterministic: the same birth always yields the
|
|
194
|
+
* same sky.
|
|
195
|
+
*
|
|
196
|
+
* `POST /v1/sky/personal` — metered (1 call).
|
|
197
|
+
*/
|
|
198
|
+
skyPersonal(birth: BirthInput, options?: SkyPersonalOptions): Promise<string>;
|
|
199
|
+
/**
|
|
200
|
+
* Render a personal-sky chart via `GET /v1/sky/personal` (birth as query
|
|
201
|
+
* params). Equivalent to {@link MysticApi.skyPersonal}; useful when you want a
|
|
202
|
+
* shareable URL shape. Returns the SVG markup as a string.
|
|
203
|
+
*/
|
|
204
|
+
skyPersonalGet(birth: BirthInput, options?: SkyPersonalOptions): Promise<string>;
|
|
205
|
+
/**
|
|
206
|
+
* Request a free, no-card API key. The key is emailed (the API responds `202`
|
|
207
|
+
* with a confirmation message — the secret itself is never returned in the
|
|
208
|
+
* body). One active key per email; 50 calls/month.
|
|
209
|
+
*
|
|
210
|
+
* `POST /v1/keys/free` — no auth required.
|
|
211
|
+
*/
|
|
212
|
+
static getFreeKey(email: string, options?: KeylessOptions): Promise<FreeKeyResponse>;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Standalone helper to request a free, no-card API key (emailed to `email`).
|
|
216
|
+
* Same as {@link MysticApi.getFreeKey}; exported for keyless call sites.
|
|
217
|
+
*
|
|
218
|
+
* `POST /v1/keys/free` — no auth required.
|
|
219
|
+
*/
|
|
220
|
+
declare function getFreeKey(email: string, options?: KeylessOptions): Promise<FreeKeyResponse>;
|
|
221
|
+
|
|
222
|
+
/** Fields used to construct a {@link MysticApiError}. */
|
|
223
|
+
interface MysticApiErrorInit {
|
|
224
|
+
status: number;
|
|
225
|
+
code: string;
|
|
226
|
+
message: string;
|
|
227
|
+
docs?: string;
|
|
228
|
+
retryAfter?: number;
|
|
229
|
+
body?: ApiErrorBody | string;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Error thrown for any non-2xx MysticAPI response (and for network failures,
|
|
233
|
+
* which surface as `status: 0`, `code: 'network_error'`).
|
|
234
|
+
*
|
|
235
|
+
* The parsed JSON error envelope (`{ error, message, docs }`) is exposed on
|
|
236
|
+
* {@link MysticApiError.body}, the machine-readable code on
|
|
237
|
+
* {@link MysticApiError.code}, and — for `429` — the `Retry-After` value in
|
|
238
|
+
* seconds on {@link MysticApiError.retryAfter}.
|
|
239
|
+
*/
|
|
240
|
+
declare class MysticApiError extends Error {
|
|
241
|
+
/** HTTP status code. `0` for a network/transport failure. */
|
|
242
|
+
readonly status: number;
|
|
243
|
+
/** Machine-readable error code (from the body's `error` field, or a synthetic one). */
|
|
244
|
+
readonly code: string;
|
|
245
|
+
/** Documentation URL surfaced by the API, when present. */
|
|
246
|
+
readonly docs?: string;
|
|
247
|
+
/** For `429`: the `Retry-After` value in seconds, when the header is present. */
|
|
248
|
+
readonly retryAfter?: number;
|
|
249
|
+
/** The parsed JSON error body, or raw text when the body was not JSON. */
|
|
250
|
+
readonly body?: ApiErrorBody | string;
|
|
251
|
+
constructor(init: MysticApiErrorInit);
|
|
252
|
+
/** True for a `401` (missing/invalid API key). */
|
|
253
|
+
get isUnauthorized(): boolean;
|
|
254
|
+
/** True for a `402` (payment required — no key and no valid x402 payment). */
|
|
255
|
+
get isPaymentRequired(): boolean;
|
|
256
|
+
/** True for a `429` (monthly allotment reached or rate limited). */
|
|
257
|
+
get isRateLimited(): boolean;
|
|
258
|
+
/**
|
|
259
|
+
* Build a {@link MysticApiError} from a failed {@link Response}, parsing the
|
|
260
|
+
* JSON error envelope and the `Retry-After` header.
|
|
261
|
+
*/
|
|
262
|
+
static fromResponse(res: Response, path: string): Promise<MysticApiError>;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export { type ApiErrorBody, type BirthInput, type BodyPosition, type BodygraphChart, type BodygraphResult, DEFAULT_BASE_URL, type FreeKeyResponse, type GatePlacement, type KeylessOptions, type MoonState, MysticApi, MysticApiError, type MysticApiErrorInit, type MysticApiOptions, type RetrogradeState, type SkyEvent, type SkyPersonalOptions, type SkyToday, type ZodiacPlacement, getFreeKey };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
|
|
24
|
+
MysticApi: () => MysticApi,
|
|
25
|
+
MysticApiError: () => MysticApiError,
|
|
26
|
+
getFreeKey: () => getFreeKey
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
|
|
30
|
+
// src/errors.ts
|
|
31
|
+
var MysticApiError = class _MysticApiError extends Error {
|
|
32
|
+
/** HTTP status code. `0` for a network/transport failure. */
|
|
33
|
+
status;
|
|
34
|
+
/** Machine-readable error code (from the body's `error` field, or a synthetic one). */
|
|
35
|
+
code;
|
|
36
|
+
/** Documentation URL surfaced by the API, when present. */
|
|
37
|
+
docs;
|
|
38
|
+
/** For `429`: the `Retry-After` value in seconds, when the header is present. */
|
|
39
|
+
retryAfter;
|
|
40
|
+
/** The parsed JSON error body, or raw text when the body was not JSON. */
|
|
41
|
+
body;
|
|
42
|
+
constructor(init) {
|
|
43
|
+
super(init.message);
|
|
44
|
+
this.name = "MysticApiError";
|
|
45
|
+
this.status = init.status;
|
|
46
|
+
this.code = init.code;
|
|
47
|
+
this.docs = init.docs;
|
|
48
|
+
this.retryAfter = init.retryAfter;
|
|
49
|
+
this.body = init.body;
|
|
50
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
51
|
+
}
|
|
52
|
+
/** True for a `401` (missing/invalid API key). */
|
|
53
|
+
get isUnauthorized() {
|
|
54
|
+
return this.status === 401;
|
|
55
|
+
}
|
|
56
|
+
/** True for a `402` (payment required — no key and no valid x402 payment). */
|
|
57
|
+
get isPaymentRequired() {
|
|
58
|
+
return this.status === 402;
|
|
59
|
+
}
|
|
60
|
+
/** True for a `429` (monthly allotment reached or rate limited). */
|
|
61
|
+
get isRateLimited() {
|
|
62
|
+
return this.status === 429;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Build a {@link MysticApiError} from a failed {@link Response}, parsing the
|
|
66
|
+
* JSON error envelope and the `Retry-After` header.
|
|
67
|
+
*/
|
|
68
|
+
static async fromResponse(res, path) {
|
|
69
|
+
const raw = await res.text().catch(() => "");
|
|
70
|
+
let body;
|
|
71
|
+
if (raw) {
|
|
72
|
+
try {
|
|
73
|
+
body = JSON.parse(raw);
|
|
74
|
+
} catch {
|
|
75
|
+
body = raw;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const envelope = typeof body === "object" && body !== null ? body : void 0;
|
|
79
|
+
const code = typeof envelope?.error === "string" && envelope.error ? envelope.error : `http_${res.status}`;
|
|
80
|
+
const message = typeof envelope?.message === "string" && envelope.message ? envelope.message : `MysticAPI request to ${path} failed with status ${res.status}`;
|
|
81
|
+
const docs = typeof envelope?.docs === "string" ? envelope.docs : void 0;
|
|
82
|
+
let retryAfter;
|
|
83
|
+
const retryHeader = res.headers.get("retry-after");
|
|
84
|
+
if (retryHeader) {
|
|
85
|
+
const seconds = Number(retryHeader);
|
|
86
|
+
if (Number.isFinite(seconds)) {
|
|
87
|
+
retryAfter = seconds;
|
|
88
|
+
} else {
|
|
89
|
+
const when = Date.parse(retryHeader);
|
|
90
|
+
if (Number.isFinite(when)) {
|
|
91
|
+
retryAfter = Math.max(0, Math.round((when - Date.now()) / 1e3));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return new _MysticApiError({ status: res.status, code, message, docs, retryAfter, body });
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// src/client.ts
|
|
100
|
+
var DEFAULT_BASE_URL = "https://mysticapi.com";
|
|
101
|
+
function resolveFetch(injected) {
|
|
102
|
+
const impl = injected ?? globalThis.fetch;
|
|
103
|
+
if (typeof impl !== "function") {
|
|
104
|
+
throw new MysticApiError({
|
|
105
|
+
status: 0,
|
|
106
|
+
code: "no_fetch",
|
|
107
|
+
message: "No global `fetch` found. Pass a `fetch` implementation in the options, or run on Node 18+, Bun, a browser, or Cloudflare Workers."
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return impl;
|
|
111
|
+
}
|
|
112
|
+
function normalizeBaseUrl(baseUrl) {
|
|
113
|
+
return (baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
114
|
+
}
|
|
115
|
+
function birthQuery(birth, options) {
|
|
116
|
+
const params = new URLSearchParams({
|
|
117
|
+
year: String(birth.year),
|
|
118
|
+
month: String(birth.month),
|
|
119
|
+
day: String(birth.day),
|
|
120
|
+
hour: String(birth.hour),
|
|
121
|
+
minute: String(birth.minute)
|
|
122
|
+
});
|
|
123
|
+
if (birth.second !== void 0) params.set("second", String(birth.second));
|
|
124
|
+
if (options?.animate !== void 0) params.set("animate", options.animate ? "true" : "false");
|
|
125
|
+
return params.toString();
|
|
126
|
+
}
|
|
127
|
+
async function requestRaw(fetchImpl, url, init, path) {
|
|
128
|
+
let res;
|
|
129
|
+
try {
|
|
130
|
+
res = await fetchImpl(url, init);
|
|
131
|
+
} catch (cause) {
|
|
132
|
+
const detail = cause instanceof Error ? cause.message : "network error";
|
|
133
|
+
throw new MysticApiError({
|
|
134
|
+
status: 0,
|
|
135
|
+
code: "network_error",
|
|
136
|
+
message: `MysticAPI request to ${path} failed: ${detail}`
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
if (!res.ok) {
|
|
140
|
+
throw await MysticApiError.fromResponse(res, path);
|
|
141
|
+
}
|
|
142
|
+
return res;
|
|
143
|
+
}
|
|
144
|
+
var MysticApi = class {
|
|
145
|
+
apiKey;
|
|
146
|
+
baseUrl;
|
|
147
|
+
fetchImpl;
|
|
148
|
+
constructor(options) {
|
|
149
|
+
if (!options || !options.apiKey) {
|
|
150
|
+
throw new MysticApiError({
|
|
151
|
+
status: 0,
|
|
152
|
+
code: "missing_api_key",
|
|
153
|
+
message: "A MysticAPI `apiKey` is required. Get a free one with MysticApi.getFreeKey(email)."
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
this.apiKey = options.apiKey;
|
|
157
|
+
this.baseUrl = normalizeBaseUrl(options.baseUrl);
|
|
158
|
+
this.fetchImpl = resolveFetch(options.fetch);
|
|
159
|
+
}
|
|
160
|
+
authHeaders(extra) {
|
|
161
|
+
const headers = new Headers(extra);
|
|
162
|
+
headers.set("Authorization", `Bearer ${this.apiKey}`);
|
|
163
|
+
return headers;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Today's universal sky: active retrogrades, moon phase + illumination,
|
|
167
|
+
* geocentric positions for 13 bodies (zodiac + Energy Blueprint gate/line),
|
|
168
|
+
* and a 30-day forward scan of retrograde stations and new/full moons.
|
|
169
|
+
*
|
|
170
|
+
* `GET /v1/sky/today` — metered (1 call).
|
|
171
|
+
*/
|
|
172
|
+
async skyToday() {
|
|
173
|
+
const res = await requestRaw(
|
|
174
|
+
this.fetchImpl,
|
|
175
|
+
`${this.baseUrl}/v1/sky/today`,
|
|
176
|
+
{ method: "GET", headers: this.authHeaders({ Accept: "application/json" }) },
|
|
177
|
+
"/v1/sky/today"
|
|
178
|
+
);
|
|
179
|
+
return await res.json();
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Compute an Energy Blueprint (Human Design) chart from a birth instant and
|
|
183
|
+
* return the full chart JSON plus a rendered body-graph SVG. Location is not
|
|
184
|
+
* required — the body-graph is location-independent.
|
|
185
|
+
*
|
|
186
|
+
* `POST /v1/bodygraph` — metered (1 call).
|
|
187
|
+
*/
|
|
188
|
+
async bodygraph(birth) {
|
|
189
|
+
const res = await requestRaw(
|
|
190
|
+
this.fetchImpl,
|
|
191
|
+
`${this.baseUrl}/v1/bodygraph`,
|
|
192
|
+
{
|
|
193
|
+
method: "POST",
|
|
194
|
+
headers: this.authHeaders({ "Content-Type": "application/json", Accept: "application/json" }),
|
|
195
|
+
body: JSON.stringify(birth)
|
|
196
|
+
},
|
|
197
|
+
"/v1/bodygraph"
|
|
198
|
+
);
|
|
199
|
+
return await res.json();
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Render a personal-sky chart from a birth instant. Returns the SVG markup as
|
|
203
|
+
* a string (`image/svg+xml`). Deterministic: the same birth always yields the
|
|
204
|
+
* same sky.
|
|
205
|
+
*
|
|
206
|
+
* `POST /v1/sky/personal` — metered (1 call).
|
|
207
|
+
*/
|
|
208
|
+
async skyPersonal(birth, options) {
|
|
209
|
+
const body = {
|
|
210
|
+
year: birth.year,
|
|
211
|
+
month: birth.month,
|
|
212
|
+
day: birth.day,
|
|
213
|
+
hour: birth.hour,
|
|
214
|
+
minute: birth.minute
|
|
215
|
+
};
|
|
216
|
+
if (birth.second !== void 0) body.second = birth.second;
|
|
217
|
+
const query = options?.animate !== void 0 ? `?animate=${options.animate ? "true" : "false"}` : "";
|
|
218
|
+
const res = await requestRaw(
|
|
219
|
+
this.fetchImpl,
|
|
220
|
+
`${this.baseUrl}/v1/sky/personal${query}`,
|
|
221
|
+
{
|
|
222
|
+
method: "POST",
|
|
223
|
+
headers: this.authHeaders({ "Content-Type": "application/json", Accept: "image/svg+xml" }),
|
|
224
|
+
body: JSON.stringify(body)
|
|
225
|
+
},
|
|
226
|
+
"/v1/sky/personal"
|
|
227
|
+
);
|
|
228
|
+
return await res.text();
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Render a personal-sky chart via `GET /v1/sky/personal` (birth as query
|
|
232
|
+
* params). Equivalent to {@link MysticApi.skyPersonal}; useful when you want a
|
|
233
|
+
* shareable URL shape. Returns the SVG markup as a string.
|
|
234
|
+
*/
|
|
235
|
+
async skyPersonalGet(birth, options) {
|
|
236
|
+
const res = await requestRaw(
|
|
237
|
+
this.fetchImpl,
|
|
238
|
+
`${this.baseUrl}/v1/sky/personal?${birthQuery(birth, options)}`,
|
|
239
|
+
{ method: "GET", headers: this.authHeaders({ Accept: "image/svg+xml" }) },
|
|
240
|
+
"/v1/sky/personal"
|
|
241
|
+
);
|
|
242
|
+
return await res.text();
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Request a free, no-card API key. The key is emailed (the API responds `202`
|
|
246
|
+
* with a confirmation message — the secret itself is never returned in the
|
|
247
|
+
* body). One active key per email; 50 calls/month.
|
|
248
|
+
*
|
|
249
|
+
* `POST /v1/keys/free` — no auth required.
|
|
250
|
+
*/
|
|
251
|
+
static async getFreeKey(email, options) {
|
|
252
|
+
return getFreeKey(email, options);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
async function getFreeKey(email, options) {
|
|
256
|
+
const fetchImpl = resolveFetch(options?.fetch);
|
|
257
|
+
const baseUrl = normalizeBaseUrl(options?.baseUrl);
|
|
258
|
+
const res = await requestRaw(
|
|
259
|
+
fetchImpl,
|
|
260
|
+
`${baseUrl}/v1/keys/free`,
|
|
261
|
+
{
|
|
262
|
+
method: "POST",
|
|
263
|
+
headers: new Headers({ "Content-Type": "application/json", Accept: "application/json" }),
|
|
264
|
+
body: JSON.stringify({ email })
|
|
265
|
+
},
|
|
266
|
+
"/v1/keys/free"
|
|
267
|
+
);
|
|
268
|
+
return await res.json();
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["/**\n * `mysticapi` — the official isomorphic TypeScript/JavaScript client for\n * MysticAPI (https://mysticapi.com): deterministic Human Design–compatible\n * bodygraphs, personal sky charts, and ephemeris.\n *\n * Zero dependencies. Runs on Node 18+, Bun, browsers, and Cloudflare Workers.\n *\n * @packageDocumentation\n */\nexport { MysticApi, getFreeKey, DEFAULT_BASE_URL } from './client.js';\nexport { MysticApiError } from './errors.js';\nexport type { MysticApiErrorInit } from './errors.js';\nexport type {\n ApiErrorBody,\n BirthInput,\n BodyPosition,\n BodygraphChart,\n BodygraphResult,\n FreeKeyResponse,\n GatePlacement,\n KeylessOptions,\n MoonState,\n MysticApiOptions,\n RetrogradeState,\n SkyEvent,\n SkyPersonalOptions,\n SkyToday,\n ZodiacPlacement,\n} from './types.js';\n","import type { ApiErrorBody } from './types.js';\n\n/** Fields used to construct a {@link MysticApiError}. */\nexport interface MysticApiErrorInit {\n status: number;\n code: string;\n message: string;\n docs?: string;\n retryAfter?: number;\n body?: ApiErrorBody | string;\n}\n\n/**\n * Error thrown for any non-2xx MysticAPI response (and for network failures,\n * which surface as `status: 0`, `code: 'network_error'`).\n *\n * The parsed JSON error envelope (`{ error, message, docs }`) is exposed on\n * {@link MysticApiError.body}, the machine-readable code on\n * {@link MysticApiError.code}, and — for `429` — the `Retry-After` value in\n * seconds on {@link MysticApiError.retryAfter}.\n */\nexport class MysticApiError extends Error {\n /** HTTP status code. `0` for a network/transport failure. */\n readonly status: number;\n /** Machine-readable error code (from the body's `error` field, or a synthetic one). */\n readonly code: string;\n /** Documentation URL surfaced by the API, when present. */\n readonly docs?: string;\n /** For `429`: the `Retry-After` value in seconds, when the header is present. */\n readonly retryAfter?: number;\n /** The parsed JSON error body, or raw text when the body was not JSON. */\n readonly body?: ApiErrorBody | string;\n\n constructor(init: MysticApiErrorInit) {\n super(init.message);\n this.name = 'MysticApiError';\n this.status = init.status;\n this.code = init.code;\n this.docs = init.docs;\n this.retryAfter = init.retryAfter;\n this.body = init.body;\n // Restore the prototype chain so `instanceof MysticApiError` holds after\n // transpilation to older targets.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n /** True for a `401` (missing/invalid API key). */\n get isUnauthorized(): boolean {\n return this.status === 401;\n }\n\n /** True for a `402` (payment required — no key and no valid x402 payment). */\n get isPaymentRequired(): boolean {\n return this.status === 402;\n }\n\n /** True for a `429` (monthly allotment reached or rate limited). */\n get isRateLimited(): boolean {\n return this.status === 429;\n }\n\n /**\n * Build a {@link MysticApiError} from a failed {@link Response}, parsing the\n * JSON error envelope and the `Retry-After` header.\n */\n static async fromResponse(res: Response, path: string): Promise<MysticApiError> {\n const raw = await res.text().catch(() => '');\n let body: ApiErrorBody | string | undefined;\n if (raw) {\n try {\n body = JSON.parse(raw) as ApiErrorBody;\n } catch {\n body = raw;\n }\n }\n\n const envelope = typeof body === 'object' && body !== null ? body : undefined;\n const code =\n typeof envelope?.error === 'string' && envelope.error ? envelope.error : `http_${res.status}`;\n const message =\n typeof envelope?.message === 'string' && envelope.message\n ? envelope.message\n : `MysticAPI request to ${path} failed with status ${res.status}`;\n const docs = typeof envelope?.docs === 'string' ? envelope.docs : undefined;\n\n let retryAfter: number | undefined;\n const retryHeader = res.headers.get('retry-after');\n if (retryHeader) {\n const seconds = Number(retryHeader);\n if (Number.isFinite(seconds)) {\n retryAfter = seconds;\n } else {\n const when = Date.parse(retryHeader);\n if (Number.isFinite(when)) {\n retryAfter = Math.max(0, Math.round((when - Date.now()) / 1000));\n }\n }\n }\n\n return new MysticApiError({ status: res.status, code, message, docs, retryAfter, body });\n }\n}\n","import { MysticApiError } from './errors.js';\nimport type {\n BirthInput,\n BodygraphResult,\n FreeKeyResponse,\n KeylessOptions,\n MysticApiOptions,\n SkyPersonalOptions,\n SkyToday,\n} from './types.js';\n\n/** Default MysticAPI base URL. */\nexport const DEFAULT_BASE_URL = 'https://mysticapi.com';\n\nfunction resolveFetch(injected?: typeof globalThis.fetch): typeof globalThis.fetch {\n const impl = injected ?? globalThis.fetch;\n if (typeof impl !== 'function') {\n throw new MysticApiError({\n status: 0,\n code: 'no_fetch',\n message:\n 'No global `fetch` found. Pass a `fetch` implementation in the options, or run on Node 18+, Bun, a browser, or Cloudflare Workers.',\n });\n }\n return impl;\n}\n\nfunction normalizeBaseUrl(baseUrl?: string): string {\n return (baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '');\n}\n\nfunction birthQuery(birth: BirthInput, options?: SkyPersonalOptions): string {\n const params = new URLSearchParams({\n year: String(birth.year),\n month: String(birth.month),\n day: String(birth.day),\n hour: String(birth.hour),\n minute: String(birth.minute),\n });\n if (birth.second !== undefined) params.set('second', String(birth.second));\n if (options?.animate !== undefined) params.set('animate', options.animate ? 'true' : 'false');\n return params.toString();\n}\n\nasync function requestRaw(\n fetchImpl: typeof globalThis.fetch,\n url: string,\n init: RequestInit,\n path: string,\n): Promise<Response> {\n let res: Response;\n try {\n res = await fetchImpl(url, init);\n } catch (cause) {\n const detail = cause instanceof Error ? cause.message : 'network error';\n throw new MysticApiError({\n status: 0,\n code: 'network_error',\n message: `MysticAPI request to ${path} failed: ${detail}`,\n });\n }\n if (!res.ok) {\n throw await MysticApiError.fromResponse(res, path);\n }\n return res;\n}\n\n/**\n * Isomorphic MysticAPI client. Zero dependencies — uses the runtime's global\n * `fetch`, so it runs unchanged on Node 18+, Bun, browsers, and Cloudflare\n * Workers.\n *\n * @example\n * ```ts\n * const mystic = new MysticApi({ apiKey: 'mk_live_...' });\n * const sky = await mystic.skyToday();\n * console.log(sky.moon.phaseName);\n * ```\n */\nexport class MysticApi {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly fetchImpl: typeof globalThis.fetch;\n\n constructor(options: MysticApiOptions) {\n if (!options || !options.apiKey) {\n throw new MysticApiError({\n status: 0,\n code: 'missing_api_key',\n message: 'A MysticAPI `apiKey` is required. Get a free one with MysticApi.getFreeKey(email).',\n });\n }\n this.apiKey = options.apiKey;\n this.baseUrl = normalizeBaseUrl(options.baseUrl);\n this.fetchImpl = resolveFetch(options.fetch);\n }\n\n private authHeaders(extra?: Record<string, string>): Headers {\n const headers = new Headers(extra);\n headers.set('Authorization', `Bearer ${this.apiKey}`);\n return headers;\n }\n\n /**\n * Today's universal sky: active retrogrades, moon phase + illumination,\n * geocentric positions for 13 bodies (zodiac + Energy Blueprint gate/line),\n * and a 30-day forward scan of retrograde stations and new/full moons.\n *\n * `GET /v1/sky/today` — metered (1 call).\n */\n async skyToday(): Promise<SkyToday> {\n const res = await requestRaw(\n this.fetchImpl,\n `${this.baseUrl}/v1/sky/today`,\n { method: 'GET', headers: this.authHeaders({ Accept: 'application/json' }) },\n '/v1/sky/today',\n );\n return (await res.json()) as SkyToday;\n }\n\n /**\n * Compute an Energy Blueprint (Human Design) chart from a birth instant and\n * return the full chart JSON plus a rendered body-graph SVG. Location is not\n * required — the body-graph is location-independent.\n *\n * `POST /v1/bodygraph` — metered (1 call).\n */\n async bodygraph(birth: BirthInput): Promise<BodygraphResult> {\n const res = await requestRaw(\n this.fetchImpl,\n `${this.baseUrl}/v1/bodygraph`,\n {\n method: 'POST',\n headers: this.authHeaders({ 'Content-Type': 'application/json', Accept: 'application/json' }),\n body: JSON.stringify(birth),\n },\n '/v1/bodygraph',\n );\n return (await res.json()) as BodygraphResult;\n }\n\n /**\n * Render a personal-sky chart from a birth instant. Returns the SVG markup as\n * a string (`image/svg+xml`). Deterministic: the same birth always yields the\n * same sky.\n *\n * `POST /v1/sky/personal` — metered (1 call).\n */\n async skyPersonal(birth: BirthInput, options?: SkyPersonalOptions): Promise<string> {\n const body: Record<string, number> = {\n year: birth.year,\n month: birth.month,\n day: birth.day,\n hour: birth.hour,\n minute: birth.minute,\n };\n if (birth.second !== undefined) body.second = birth.second;\n const query = options?.animate !== undefined ? `?animate=${options.animate ? 'true' : 'false'}` : '';\n const res = await requestRaw(\n this.fetchImpl,\n `${this.baseUrl}/v1/sky/personal${query}`,\n {\n method: 'POST',\n headers: this.authHeaders({ 'Content-Type': 'application/json', Accept: 'image/svg+xml' }),\n body: JSON.stringify(body),\n },\n '/v1/sky/personal',\n );\n return await res.text();\n }\n\n /**\n * Render a personal-sky chart via `GET /v1/sky/personal` (birth as query\n * params). Equivalent to {@link MysticApi.skyPersonal}; useful when you want a\n * shareable URL shape. Returns the SVG markup as a string.\n */\n async skyPersonalGet(birth: BirthInput, options?: SkyPersonalOptions): Promise<string> {\n const res = await requestRaw(\n this.fetchImpl,\n `${this.baseUrl}/v1/sky/personal?${birthQuery(birth, options)}`,\n { method: 'GET', headers: this.authHeaders({ Accept: 'image/svg+xml' }) },\n '/v1/sky/personal',\n );\n return await res.text();\n }\n\n /**\n * Request a free, no-card API key. The key is emailed (the API responds `202`\n * with a confirmation message — the secret itself is never returned in the\n * body). One active key per email; 50 calls/month.\n *\n * `POST /v1/keys/free` — no auth required.\n */\n static async getFreeKey(email: string, options?: KeylessOptions): Promise<FreeKeyResponse> {\n return getFreeKey(email, options);\n }\n}\n\n/**\n * Standalone helper to request a free, no-card API key (emailed to `email`).\n * Same as {@link MysticApi.getFreeKey}; exported for keyless call sites.\n *\n * `POST /v1/keys/free` — no auth required.\n */\nexport async function getFreeKey(email: string, options?: KeylessOptions): Promise<FreeKeyResponse> {\n const fetchImpl = resolveFetch(options?.fetch);\n const baseUrl = normalizeBaseUrl(options?.baseUrl);\n const res = await requestRaw(\n fetchImpl,\n `${baseUrl}/v1/keys/free`,\n {\n method: 'POST',\n headers: new Headers({ 'Content-Type': 'application/json', Accept: 'application/json' }),\n body: JSON.stringify({ email }),\n },\n '/v1/keys/free',\n );\n return (await res.json()) as FreeKeyResponse;\n}\n"],"mappings":"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","names":[]}
|