@baziapi/sdk 1.0.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.
@@ -0,0 +1,951 @@
1
+ /**
2
+ * @file HttpClient.ts
3
+ * @description Native fetch-based HTTP client with timeout, retry, and error mapping.
4
+ * No external HTTP library dependencies — works in Node 18+, Bun, Deno, and browsers.
5
+ */
6
+ /** Internal configuration for the HttpClient. */
7
+ interface HttpClientConfig {
8
+ /** Root API URL without trailing slash. e.g. `https://api.bazi.com` */
9
+ readonly baseUrl: string;
10
+ /** API key for Bearer token authentication. */
11
+ readonly apiKey: string;
12
+ /** Request timeout in milliseconds. */
13
+ readonly timeout: number;
14
+ /** Maximum retry attempts for retryable failures. */
15
+ readonly retries: number;
16
+ /** Base delay in milliseconds for exponential backoff. */
17
+ readonly retryDelay: number;
18
+ /** Optional callback invoked on every SDK error. */
19
+ readonly onError?: ((error: Error) => void) | undefined;
20
+ }
21
+ /**
22
+ * Lightweight, native-fetch HTTP client.
23
+ * Handles authorization headers, timeouts, JSON parsing, error mapping, and retries.
24
+ */
25
+ declare class HttpClient {
26
+ private readonly config;
27
+ constructor(config: HttpClientConfig);
28
+ /**
29
+ * Performs a GET request.
30
+ * @param path - URL path relative to baseUrl.
31
+ * @param bearerToken - Optional JWT bearer token.
32
+ */
33
+ get<T>(path: string, bearerToken?: string): Promise<T>;
34
+ /**
35
+ * Performs a POST request.
36
+ * @param path - URL path relative to baseUrl.
37
+ * @param body - JSON request body.
38
+ * @param bearerToken - Optional JWT bearer token.
39
+ */
40
+ post<T>(path: string, body?: unknown, bearerToken?: string): Promise<T>;
41
+ /**
42
+ * Performs a PATCH request.
43
+ * @param path - URL path relative to baseUrl.
44
+ * @param body - JSON request body.
45
+ * @param bearerToken - Optional JWT bearer token.
46
+ */
47
+ patch<T>(path: string, body?: unknown, bearerToken?: string): Promise<T>;
48
+ /**
49
+ * Performs a DELETE request.
50
+ * @param path - URL path relative to baseUrl.
51
+ * @param bearerToken - Optional JWT bearer token.
52
+ */
53
+ delete<T>(path: string, bearerToken?: string): Promise<T>;
54
+ private buildHeaders;
55
+ private buildUrl;
56
+ private executeRequest;
57
+ private request;
58
+ }
59
+
60
+ /**
61
+ * @file request.ts
62
+ * @description All SDK request DTOs. Mirrors backend Zod schemas exactly.
63
+ * All string fields use `Readonly` to prevent consumer mutation.
64
+ */
65
+ /**
66
+ * Input required to calculate BaZi (Four Pillars of Destiny).
67
+ * Mirrors `baziValidationSchema` from the backend.
68
+ */
69
+ interface BaziCalculateRequest {
70
+ /** Birth date in YYYY-MM-DD format. Required. */
71
+ readonly birthDate: string;
72
+ /** Birth time in HH:mm format. Optional — defaults to 12:00 on the backend. */
73
+ readonly birthTime?: string;
74
+ /** Biological gender. Required for luck pillar direction calculation. */
75
+ readonly gender: 'male' | 'female';
76
+ /**
77
+ * IANA timezone identifier.
78
+ * @default 'Asia/Shanghai'
79
+ * @example 'Asia/Dhaka', 'America/New_York', 'Europe/London'
80
+ */
81
+ readonly timezone?: string;
82
+ /**
83
+ * Response language.
84
+ * `'en'` returns English labels; `'zh'` returns Chinese characters.
85
+ * @default 'en'
86
+ */
87
+ readonly language?: 'en' | 'zh';
88
+ }
89
+ /**
90
+ * Request body for user registration.
91
+ * Mirrors `registerZodSchema` from the backend.
92
+ */
93
+ interface RegisterRequest {
94
+ /** Display name. Required. */
95
+ readonly name: string;
96
+ /** Valid email address. Required. */
97
+ readonly email: string;
98
+ /** Password. Minimum 6 characters. Required. */
99
+ readonly password: string;
100
+ /** ISO 3166-1 alpha-2 country code or full name. Optional. */
101
+ readonly country?: string;
102
+ }
103
+ /**
104
+ * Request body for user login.
105
+ * Mirrors `loginZodSchema` from the backend.
106
+ */
107
+ interface LoginRequest {
108
+ /** Registered email address. */
109
+ readonly email: string;
110
+ /** Account password. */
111
+ readonly password: string;
112
+ }
113
+ /**
114
+ * Request body for email verification via OTP.
115
+ * Mirrors `verifyEmailZodSchema` from the backend.
116
+ */
117
+ interface VerifyEmailRequest {
118
+ /** Email address to verify. */
119
+ readonly email: string;
120
+ /** 6-character OTP received via email. */
121
+ readonly otp: string;
122
+ }
123
+ /**
124
+ * Request body for initiating a password reset.
125
+ * Mirrors `forgotPasswordZodSchema` from the backend.
126
+ */
127
+ interface ForgotPasswordRequest {
128
+ /** Registered email address to send reset OTP. */
129
+ readonly email: string;
130
+ }
131
+ /**
132
+ * Request body for completing a password reset.
133
+ * Mirrors `resetPasswordZodSchema` from the backend.
134
+ */
135
+ interface ResetPasswordRequest {
136
+ /** Email address associated with the account. */
137
+ readonly email: string;
138
+ /** 6-character OTP received via email. */
139
+ readonly otp: string;
140
+ /** New password. Minimum 6 characters. */
141
+ readonly newPassword: string;
142
+ }
143
+ /**
144
+ * Request body for changing password while authenticated.
145
+ * Mirrors `changePasswordZodSchema` from the backend.
146
+ */
147
+ interface ChangePasswordRequest {
148
+ /** Current account password. */
149
+ readonly oldPassword: string;
150
+ /** New password. Minimum 6 characters. */
151
+ readonly newPassword: string;
152
+ }
153
+
154
+ /**
155
+ * @file response.ts
156
+ * @description All SDK response types. Mirrors backend bazi.interface.ts and auth.interface.ts exactly.
157
+ * Every nullable field on the backend is typed as `T | null` here.
158
+ */
159
+ /** Standard API response envelope returned by every endpoint. */
160
+ interface ApiResponse<T> {
161
+ success: boolean;
162
+ message: string | null;
163
+ data: T | null;
164
+ }
165
+ /** The original input echoed back in the response. */
166
+ interface BaziInput {
167
+ birthDate: string;
168
+ birthTime: string;
169
+ gender: 'male' | 'female';
170
+ timezone: string;
171
+ language: string;
172
+ }
173
+ /** Solar (Gregorian) calendar information. */
174
+ interface SolarInfo {
175
+ solarYear: number;
176
+ solarMonth: number;
177
+ solarDay: number;
178
+ solarHour: number;
179
+ solarMinute: number;
180
+ solarDateTime: string;
181
+ weekDay: string;
182
+ }
183
+ /** Lunar calendar information. */
184
+ interface LunarInfo {
185
+ lunarYear: number;
186
+ lunarMonth: number;
187
+ lunarDay: number;
188
+ leapMonth: number;
189
+ chineseDate: string;
190
+ }
191
+ /** The Four Pillars (Year, Month, Day, Hour). */
192
+ interface FourPillars {
193
+ yearPillar: string;
194
+ monthPillar: string;
195
+ dayPillar: string;
196
+ hourPillar: string;
197
+ }
198
+ /** Advanced pillars: TaiYuan, MingGong, ShenGong. */
199
+ interface AdvancedPillars {
200
+ taiYuan: string;
201
+ mingGong: string;
202
+ shenGong: string;
203
+ }
204
+ /** Heavenly Stems for each pillar. */
205
+ interface HeavenlyStems {
206
+ yearStem: string;
207
+ monthStem: string;
208
+ dayStem: string;
209
+ hourStem: string;
210
+ }
211
+ /** Earthly Branches for each pillar. */
212
+ interface EarthlyBranches {
213
+ yearBranch: string;
214
+ monthBranch: string;
215
+ dayBranch: string;
216
+ hourBranch: string;
217
+ }
218
+ /** Five Elements (WuXing) mapping and statistics. */
219
+ interface FiveElements {
220
+ yearElement: string;
221
+ monthElement: string;
222
+ dayElement: string;
223
+ hourElement: string;
224
+ /** Percentage breakdown: `{ Wood: '25%', Fire: '0%', ... }` */
225
+ statistics: Record<string, string>;
226
+ }
227
+ /** Hidden Stems inside each Earthly Branch. */
228
+ interface HiddenStems {
229
+ yearHiddenStems: string[];
230
+ monthHiddenStems: string[];
231
+ dayHiddenStems: string[];
232
+ hourHiddenStems: string[];
233
+ }
234
+ /** Ten Gods (ShiShen) for each pillar. */
235
+ interface TenGods {
236
+ yearTenGod: string;
237
+ monthTenGod: string;
238
+ dayTenGod: string;
239
+ hourTenGod: string;
240
+ /** Percentage distribution of each Ten God across the chart. */
241
+ distribution?: Record<string, string>;
242
+ }
243
+ /** NaYin (Sound Element) for each pillar. */
244
+ interface NaYin {
245
+ yearNaYin: string;
246
+ monthNaYin: string;
247
+ dayNaYin: string;
248
+ hourNaYin: string;
249
+ }
250
+ /** Chinese Zodiac information. */
251
+ interface Zodiac {
252
+ chineseZodiac: string;
253
+ animal: string;
254
+ }
255
+ /** Western astrological constellation. */
256
+ interface Constellation {
257
+ westernConstellation: string;
258
+ }
259
+ /** Current, previous, and next solar terms (JieQi). */
260
+ interface SolarTerms {
261
+ currentSolarTerm: string | null;
262
+ previousSolarTerm: string | null;
263
+ nextSolarTerm: string | null;
264
+ }
265
+ /** A single year within a Luck Pillar cycle. */
266
+ interface LiuNian {
267
+ year: number;
268
+ age: number;
269
+ pillar: string;
270
+ }
271
+ /** A single 10-year Luck Pillar (DaYun). */
272
+ interface LuckPillarItem {
273
+ age: number;
274
+ pillar: string;
275
+ annualLuck?: LiuNian[];
276
+ }
277
+ /** Full Luck Pillar data including minor luck and direction. */
278
+ interface LuckPillars {
279
+ direction: string | null;
280
+ forward: boolean;
281
+ startingAge: number;
282
+ startingDate: string | null;
283
+ pillars: LuckPillarItem[];
284
+ minorLuck: LiuNian[];
285
+ }
286
+ /** Auspicious and inauspicious stars / shen sha. */
287
+ interface GodsAndStars {
288
+ nobleman: string[] | null;
289
+ peachBlossom: string[] | null;
290
+ academicStar: string[] | null;
291
+ travelHorse: string[] | null;
292
+ generalStar: string[] | null;
293
+ }
294
+ /** Branch interaction patterns within the chart. */
295
+ interface Interactions {
296
+ clashes: string[];
297
+ combinations: string[];
298
+ punishments: string[];
299
+ harms: string[];
300
+ }
301
+ /** Deep analytical data derived from the chart. */
302
+ interface Analysis {
303
+ dayMasterStrength: string | null;
304
+ strongestElement: string | null;
305
+ weakestElement: string | null;
306
+ missingElements: string[];
307
+ balanced: boolean | null;
308
+ favorableElements: string[];
309
+ unfavorableElements: string[];
310
+ yongShen: string | null;
311
+ voidBranch: string | null;
312
+ twelveGrowthPhases: string[] | null;
313
+ godsAndStars: GodsAndStars | null;
314
+ interactions: Interactions | null;
315
+ }
316
+ /** High-level life predictions derived from the chart. */
317
+ interface LifePredictions {
318
+ careerDirection: string | null;
319
+ wealthPotential: string | null;
320
+ healthFocus: string[];
321
+ }
322
+ /** Annual luck overlay for the current year. */
323
+ interface CurrentAnnualLuck {
324
+ currentYear: number;
325
+ annualPillar: string;
326
+ overallFortune: string;
327
+ keyEvents: string[];
328
+ }
329
+ /**
330
+ * Complete BaZi calculation response.
331
+ * Mirrors `IBaziResponseData` from the backend exactly.
332
+ * Fields can be `null` for FREE-tier users after the trial period.
333
+ */
334
+ interface BaziCalculateResponse {
335
+ input: BaziInput;
336
+ solar: SolarInfo | null;
337
+ lunar: LunarInfo | null;
338
+ pillars: FourPillars | null;
339
+ advancedPillars: AdvancedPillars | null;
340
+ heavenlyStems: HeavenlyStems | null;
341
+ earthlyBranches: EarthlyBranches | null;
342
+ fiveElements: FiveElements | null;
343
+ hiddenStems: HiddenStems | null;
344
+ tenGods: TenGods | null;
345
+ naYin: NaYin | null;
346
+ zodiac: Zodiac | null;
347
+ constellation: Constellation | null;
348
+ solarTerms: SolarTerms | null;
349
+ luckPillars: LuckPillars | null;
350
+ analysis: Analysis | null;
351
+ lifePredictions: LifePredictions | null;
352
+ currentAnnualLuck: CurrentAnnualLuck | null;
353
+ }
354
+ /** User object returned after authentication. */
355
+ interface AuthUser {
356
+ id: string;
357
+ name: string;
358
+ email: string;
359
+ role: string;
360
+ isEmailVerified: boolean;
361
+ }
362
+ /** Response from login endpoint. */
363
+ interface LoginResponse {
364
+ accessToken: string;
365
+ refreshToken: string;
366
+ user: AuthUser;
367
+ }
368
+ /** Response from refresh-token endpoint. */
369
+ interface RefreshTokenResponse {
370
+ accessToken: string;
371
+ }
372
+ /** A single API key item. */
373
+ interface ApiKeyItem {
374
+ id: string;
375
+ prefix: string;
376
+ name: string | null;
377
+ isActive: boolean;
378
+ createdAt: string;
379
+ lastUsedAt: string | null;
380
+ }
381
+ /** Response from generate API key endpoint. */
382
+ interface GeneratedApiKey {
383
+ id: string;
384
+ prefix: string;
385
+ /** The full raw key — only returned once. Store it securely. */
386
+ key: string;
387
+ name: string | null;
388
+ isActive: boolean;
389
+ createdAt: string;
390
+ }
391
+ /** Response from list API keys endpoint. */
392
+ type ApiKeyListResponse = ApiKeyItem[];
393
+ /** Full user profile from /auth/me. */
394
+ interface UserProfile {
395
+ id: string;
396
+ name: string;
397
+ email: string;
398
+ role: string;
399
+ country: string | null;
400
+ isEmailVerified: boolean;
401
+ createdAt: string;
402
+ updatedAt: string;
403
+ }
404
+
405
+ /**
406
+ * @file resources/bazi.ts
407
+ * @description BaZi calculation resource. Handles POST /api/v1/bazi/calculate.
408
+ */
409
+
410
+ /**
411
+ * Resource class for BaZi (Four Pillars of Destiny) calculations.
412
+ * Access via `client.bazi`.
413
+ */
414
+ declare class BaziResource {
415
+ private readonly http;
416
+ /** @internal */
417
+ constructor(http: HttpClient);
418
+ /**
419
+ * Calculate BaZi (Four Pillars of Destiny) for a given birth date and time.
420
+ *
421
+ * Validates input client-side before sending the request.
422
+ * Requires an API key set on the client.
423
+ *
424
+ * @param input - The birth information required for calculation.
425
+ * @returns A promise resolving to the full BaZi analysis result.
426
+ *
427
+ * @throws {ValidationError} If the input fails client-side validation.
428
+ * @throws {ApiError} If the server rejects the request (4xx/5xx).
429
+ * @throws {TimeoutError} If the request exceeds the configured timeout.
430
+ * @throws {NetworkError} If a network-level failure occurs.
431
+ *
432
+ * @example
433
+ * ```typescript
434
+ * const result = await client.bazi.calculate({
435
+ * birthDate: '1998-08-12',
436
+ * birthTime: '10:30',
437
+ * gender: 'male',
438
+ * timezone: 'Asia/Dhaka',
439
+ * language: 'en',
440
+ * });
441
+ *
442
+ * console.log(result.pillars);
443
+ * console.log(result.luckPillars?.pillars);
444
+ * ```
445
+ */
446
+ calculate(input: BaziCalculateRequest): Promise<BaziCalculateResponse>;
447
+ }
448
+
449
+ /**
450
+ * @file resources/auth.ts
451
+ * @description Authentication resource. Handles all /api/v1/auth/* endpoints.
452
+ */
453
+
454
+ /**
455
+ * Resource class for authentication operations.
456
+ * Access via `client.auth`.
457
+ *
458
+ * JWT tokens returned by `login()` must be stored by the consumer
459
+ * and passed back via `bearerToken` on protected calls.
460
+ */
461
+ declare class AuthResource {
462
+ private readonly http;
463
+ /** @internal */
464
+ constructor(http: HttpClient);
465
+ /**
466
+ * Register a new user account.
467
+ *
468
+ * @param input - Registration data including name, email, and password.
469
+ * @returns A promise resolving to `null` on success (email verification required).
470
+ *
471
+ * @throws {ValidationError} If input is invalid.
472
+ * @throws {ApiError} If the email is already registered (409).
473
+ *
474
+ * @example
475
+ * ```typescript
476
+ * await client.auth.register({
477
+ * name: 'Jane Doe',
478
+ * email: 'jane@example.com',
479
+ * password: 'secret123',
480
+ * });
481
+ * ```
482
+ */
483
+ register(input: RegisterRequest): Promise<null>;
484
+ /**
485
+ * Verify an email address using the OTP sent during registration.
486
+ *
487
+ * @param input - Email address and 6-digit OTP.
488
+ * @returns A promise resolving to `null` on success.
489
+ *
490
+ * @throws {ValidationError} If input is invalid.
491
+ * @throws {ApiError} If OTP is incorrect or expired (400).
492
+ */
493
+ verifyEmail(input: VerifyEmailRequest): Promise<null>;
494
+ /**
495
+ * Log in with email and password.
496
+ *
497
+ * @param input - Email and password credentials.
498
+ * @returns A promise resolving to access token, refresh token, and user data.
499
+ *
500
+ * @throws {ValidationError} If input is invalid.
501
+ * @throws {ApiError} If credentials are incorrect (401).
502
+ *
503
+ * @example
504
+ * ```typescript
505
+ * const { accessToken, user } = await client.auth.login({
506
+ * email: 'jane@example.com',
507
+ * password: 'secret123',
508
+ * });
509
+ * ```
510
+ */
511
+ login(input: LoginRequest): Promise<LoginResponse>;
512
+ /**
513
+ * Refresh an expired access token using a valid refresh token.
514
+ *
515
+ * @param refreshToken - A valid refresh token previously issued by `login()`.
516
+ * @returns A promise resolving to a new access token.
517
+ *
518
+ * @throws {ApiError} If the refresh token is invalid or expired (401).
519
+ */
520
+ refreshToken(refreshToken: string): Promise<RefreshTokenResponse>;
521
+ /**
522
+ * Initiate a password reset flow by requesting an OTP via email.
523
+ *
524
+ * @param input - Email address of the account to reset.
525
+ * @returns A promise resolving to `null` on success.
526
+ *
527
+ * @throws {ValidationError} If the email is invalid.
528
+ * @throws {ApiError} If the email is not registered (404).
529
+ */
530
+ forgotPassword(input: ForgotPasswordRequest): Promise<null>;
531
+ /**
532
+ * Complete a password reset using the OTP received via email.
533
+ *
534
+ * @param input - Email, OTP, and new password.
535
+ * @returns A promise resolving to `null` on success.
536
+ *
537
+ * @throws {ValidationError} If input is invalid.
538
+ * @throws {ApiError} If OTP is incorrect or expired (400).
539
+ */
540
+ resetPassword(input: ResetPasswordRequest): Promise<null>;
541
+ /**
542
+ * Change the authenticated user's password.
543
+ * Requires a valid JWT access token.
544
+ *
545
+ * @param input - Old password and new password.
546
+ * @param bearerToken - Valid JWT access token from `login()`.
547
+ * @returns A promise resolving to `null` on success.
548
+ *
549
+ * @throws {ValidationError} If input is invalid.
550
+ * @throws {ApiError} If old password is incorrect (401) or token is invalid.
551
+ */
552
+ changePassword(input: ChangePasswordRequest, bearerToken: string): Promise<null>;
553
+ /**
554
+ * Retrieve the authenticated user's profile.
555
+ * Requires a valid JWT access token.
556
+ *
557
+ * @param bearerToken - Valid JWT access token from `login()`.
558
+ * @returns A promise resolving to the user profile.
559
+ *
560
+ * @throws {ApiError} If the token is invalid or expired (401).
561
+ *
562
+ * @example
563
+ * ```typescript
564
+ * const profile = await client.auth.me(accessToken);
565
+ * console.log(profile.email);
566
+ * ```
567
+ */
568
+ me(bearerToken: string): Promise<UserProfile>;
569
+ /**
570
+ * Log out the authenticated user, invalidating their session.
571
+ * Requires a valid JWT access token.
572
+ *
573
+ * @param bearerToken - Valid JWT access token from `login()`.
574
+ * @returns A promise resolving to `null` on success.
575
+ *
576
+ * @throws {ApiError} If the token is invalid or expired (401).
577
+ */
578
+ logout(bearerToken: string): Promise<null>;
579
+ }
580
+
581
+ /**
582
+ * @file resources/apiKey.ts
583
+ * @description API Key management resource. Handles all /api/v1/api-keys/* endpoints.
584
+ */
585
+
586
+ /**
587
+ * Resource class for API Key management operations.
588
+ * Access via `client.apiKeys`.
589
+ *
590
+ * All methods require a valid JWT `bearerToken` from `client.auth.login()`.
591
+ */
592
+ declare class ApiKeyResource {
593
+ private readonly http;
594
+ /** @internal */
595
+ constructor(http: HttpClient);
596
+ /**
597
+ * List all API keys associated with the authenticated user's account.
598
+ * Only the key prefix is returned — not the full raw key.
599
+ *
600
+ * @param bearerToken - Valid JWT access token from `client.auth.login()`.
601
+ * @returns A promise resolving to an array of API key metadata.
602
+ *
603
+ * @throws {ApiError} If the token is invalid or expired (401).
604
+ *
605
+ * @example
606
+ * ```typescript
607
+ * const keys = await client.apiKeys.list(accessToken);
608
+ * keys.forEach(key => console.log(key.prefix, key.isActive));
609
+ * ```
610
+ */
611
+ list(bearerToken: string): Promise<ApiKeyListResponse>;
612
+ /**
613
+ * Generate a new API key for the authenticated user.
614
+ *
615
+ * **Important:** The full raw key is returned only once in this response.
616
+ * Store it securely — it cannot be retrieved again.
617
+ *
618
+ * @param bearerToken - Valid JWT access token from `client.auth.login()`.
619
+ * @returns A promise resolving to the newly created API key including the full raw key.
620
+ *
621
+ * @throws {ApiError} If the token is invalid or the user's plan limit is reached.
622
+ *
623
+ * @example
624
+ * ```typescript
625
+ * const { key, prefix } = await client.apiKeys.create(accessToken);
626
+ * // Store `key` securely — it won't be shown again
627
+ * console.log('Your API key:', key);
628
+ * ```
629
+ */
630
+ create(bearerToken: string): Promise<GeneratedApiKey>;
631
+ /**
632
+ * Revoke (deactivate) an API key by its ID.
633
+ * Revoked keys are permanently disabled and cannot be re-activated.
634
+ *
635
+ * @param keyId - The ID of the API key to revoke.
636
+ * @param bearerToken - Valid JWT access token from `client.auth.login()`.
637
+ * @returns A promise resolving to the revoked API key metadata.
638
+ *
639
+ * @throws {ApiError} If the key is not found (404) or doesn't belong to the user (403).
640
+ *
641
+ * @example
642
+ * ```typescript
643
+ * await client.apiKeys.revoke(keyId, accessToken);
644
+ * ```
645
+ */
646
+ revoke(keyId: string, bearerToken: string): Promise<ApiKeyItem>;
647
+ }
648
+
649
+ /**
650
+ * @file BaziError.ts
651
+ * @description Base error class for all SDK errors.
652
+ * Every error thrown by the SDK extends this class.
653
+ */
654
+ /**
655
+ * Discriminant union type for all SDK error kinds.
656
+ */
657
+ type BaziErrorKind = 'api_error' | 'validation_error' | 'timeout_error' | 'network_error';
658
+ /**
659
+ * Abstract base class for all BaZi SDK errors.
660
+ * Consumers can use `instanceof BaziError` to catch any SDK error.
661
+ */
662
+ declare abstract class BaziError extends Error {
663
+ /** Machine-readable error kind for programmatic handling. */
664
+ abstract readonly kind: BaziErrorKind;
665
+ constructor(message: string);
666
+ }
667
+
668
+ /**
669
+ * @file constants.ts
670
+ * @description Shared SDK constants.
671
+ */
672
+ /**
673
+ * The BaZi backend API version prefix.
674
+ * Used by resource classes to construct URL paths.
675
+ */
676
+ declare const API_VERSION: "v1";
677
+
678
+ /**
679
+ * @file WebhookService.ts
680
+ * @description Isomorphic HMAC-SHA256 Webhook signature verification.
681
+ * Works seamlessly across Node.js (18+), Bun, Deno, Cloudflare Workers, and Browser environments.
682
+ */
683
+ interface VerifySignatureOptions {
684
+ /**
685
+ * Raw request body as a string or Uint8Array/Buffer.
686
+ */
687
+ payload: string | Uint8Array;
688
+ /**
689
+ * The signature header sent with the webhook (e.g. from `x-bazi-signature` or `x-webhook-signature`).
690
+ */
691
+ signature: string;
692
+ /**
693
+ * Your webhook endpoint signing secret (configured in the BaZi dashboard).
694
+ */
695
+ secret: string;
696
+ /**
697
+ * Optional tolerance in seconds to prevent replay attacks (if signature contains timestamp `t=...,v1=...`).
698
+ */
699
+ tolerance?: number;
700
+ }
701
+ /**
702
+ * Webhook signature verification service.
703
+ */
704
+ declare class WebhookService {
705
+ /**
706
+ * Verifies an incoming webhook HMAC-SHA256 signature.
707
+ *
708
+ * @param options - Verification options including payload, signature, and secret.
709
+ * @returns `true` if the signature is valid; `false` otherwise.
710
+ *
711
+ * @example
712
+ * ```typescript
713
+ * import { BaziClient } from '@bazi/sdk';
714
+ *
715
+ * const client = new BaziClient();
716
+ * const isValid = await client.webhooks.verifySignature({
717
+ * payload: rawBody,
718
+ * signature: req.headers['x-bazi-signature'],
719
+ * secret: process.env.BAZI_WEBHOOK_SECRET!,
720
+ * });
721
+ *
722
+ * if (!isValid) {
723
+ * return res.status(401).send('Invalid signature');
724
+ * }
725
+ * ```
726
+ */
727
+ verifySignature(options: VerifySignatureOptions): Promise<boolean>;
728
+ /**
729
+ * Computes an HMAC-SHA256 digest in hex string format using Web Crypto API.
730
+ *
731
+ * @param payload - Raw request payload.
732
+ * @param secret - Secret key.
733
+ * @returns Hexadecimal digest string.
734
+ */
735
+ computeHmac(payload: string | Uint8Array, secret: string): Promise<string>;
736
+ }
737
+ /**
738
+ * Standalone helper function for verifying webhook signatures without instantiating `BaziClient`.
739
+ *
740
+ * @param options - Webhook verification options.
741
+ * @returns `true` if valid, `false` otherwise.
742
+ */
743
+ declare function verifyWebhookSignature(options: VerifySignatureOptions): Promise<boolean>;
744
+
745
+ /**
746
+ * @file client.ts
747
+ * @description BaziClient — the main entry point for the BaZi API SDK.
748
+ */
749
+
750
+ /**
751
+ * Configuration options for `BaziClient`.
752
+ * All fields except `apiKey` are optional with safe defaults.
753
+ */
754
+ interface BaziClientOptions {
755
+ /**
756
+ * Your BaZi API key (prefix: `bazi_`).
757
+ * Required for all BaZi calculation requests.
758
+ * Optional for auth-only use cases.
759
+ */
760
+ readonly apiKey?: string;
761
+ /**
762
+ * Base URL of the BaZi API server.
763
+ * @default 'https://api.bazi.dev'
764
+ */
765
+ readonly baseUrl?: string;
766
+ /**
767
+ * Request timeout in milliseconds.
768
+ * Throws `TimeoutError` when exceeded.
769
+ * @default 10000
770
+ */
771
+ readonly timeout?: number;
772
+ /**
773
+ * Maximum number of retry attempts for transient failures (network errors, 5xx, 429).
774
+ * @default 3
775
+ */
776
+ readonly retries?: number;
777
+ /**
778
+ * Base delay in milliseconds between retry attempts (exponential backoff).
779
+ * Actual delay = `retryDelay * 2^attempt`.
780
+ * @default 500
781
+ */
782
+ readonly retryDelay?: number;
783
+ /**
784
+ * Optional callback invoked whenever the SDK throws an error.
785
+ * Useful for logging and monitoring integrations.
786
+ *
787
+ * @example
788
+ * ```typescript
789
+ * new BaziClient({
790
+ * apiKey: 'bazi_xxx',
791
+ * onError: (err) => Sentry.captureException(err),
792
+ * });
793
+ * ```
794
+ */
795
+ readonly onError?: (error: BaziError) => void;
796
+ }
797
+
798
+ declare class BaziClient {
799
+ private readonly httpClient;
800
+ /**
801
+ * BaZi calculation resource.
802
+ * Endpoint: `POST /api/v1/bazi/calculate`
803
+ */
804
+ readonly bazi: BaziResource;
805
+ /**
806
+ * Authentication resource.
807
+ * Endpoints: register, login, logout, verifyEmail, forgotPassword, resetPassword, changePassword, me
808
+ */
809
+ readonly auth: AuthResource;
810
+ /**
811
+ * API Key management resource.
812
+ * Endpoints: list, create, revoke
813
+ */
814
+ readonly apiKeys: ApiKeyResource;
815
+ /**
816
+ * Webhook utilities for verifying HMAC-SHA256 signatures.
817
+ */
818
+ readonly webhooks: WebhookService;
819
+ /**
820
+ * Creates a new BaziClient instance.
821
+ *
822
+ * @param options - Client configuration options.
823
+ *
824
+ * @example
825
+ * ```typescript
826
+ * // Production usage
827
+ * const client = new BaziClient({ apiKey: 'bazi_xxxx' });
828
+ *
829
+ * // Development / self-hosted
830
+ * const client = new BaziClient({
831
+ * apiKey: 'bazi_xxxx',
832
+ * baseUrl: 'http://localhost:5000',
833
+ * timeout: 30_000,
834
+ * retries: 1,
835
+ * });
836
+ * ```
837
+ */
838
+ constructor(options?: BaziClientOptions);
839
+ /**
840
+ * Direct convenience method to calculate BaZi (Four Pillars of Destiny).
841
+ * Shortcut for `client.bazi.calculate(input)`.
842
+ *
843
+ * @param input - The birth information required for calculation.
844
+ * @returns A promise resolving to the full BaZi analysis result.
845
+ */
846
+ calculate(input: BaziCalculateRequest): Promise<BaziCalculateResponse>;
847
+ }
848
+
849
+ /**
850
+ * @file ApiError.ts
851
+ * @description All SDK error subclasses: ApiError, ValidationError, TimeoutError, NetworkError.
852
+ */
853
+
854
+ /**
855
+ * Thrown when the BaZi API returns a non-2xx HTTP response.
856
+ *
857
+ * @example
858
+ * ```typescript
859
+ * try {
860
+ * await client.bazi.calculate({ ... });
861
+ * } catch (error) {
862
+ * if (error instanceof ApiError) {
863
+ * console.error(error.statusCode, error.message);
864
+ * console.error(error.errors); // server validation details
865
+ * }
866
+ * }
867
+ * ```
868
+ */
869
+ declare class ApiError extends BaziError {
870
+ readonly kind: BaziErrorKind;
871
+ /** HTTP status code returned by the server. */
872
+ readonly statusCode: number;
873
+ /** Detailed server-side validation errors, if any. */
874
+ readonly errors: unknown[] | undefined;
875
+ /** Request ID from the `X-Request-ID` response header, if present. */
876
+ readonly requestId: string | undefined;
877
+ /**
878
+ * Raw `Retry-After` header value from the server response.
879
+ * Used internally by the retry layer — not intended for consumer use.
880
+ * @internal
881
+ */
882
+ readonly _retryAfter: string | null;
883
+ constructor(statusCode: number, message: string, errors?: unknown[], requestId?: string, retryAfter?: string | null);
884
+ }
885
+ /**
886
+ * Thrown when client-side input validation fails before a request is sent.
887
+ * The request is never made to the network in this case.
888
+ *
889
+ * @example
890
+ * ```typescript
891
+ * try {
892
+ * await client.bazi.calculate({ birthDate: 'bad-date', gender: 'male' });
893
+ * } catch (error) {
894
+ * if (error instanceof ValidationError) {
895
+ * console.error('Bad input:', error.message);
896
+ * console.error('Field:', error.field);
897
+ * }
898
+ * }
899
+ * ```
900
+ */
901
+ declare class ValidationError extends BaziError {
902
+ readonly kind: BaziErrorKind;
903
+ /** The name of the field that failed validation. */
904
+ readonly field: string;
905
+ constructor(field: string, message: string);
906
+ }
907
+ /**
908
+ * Thrown when a request exceeds the configured `timeout` option.
909
+ *
910
+ * @example
911
+ * ```typescript
912
+ * const client = new BaziClient({ apiKey: '...', timeout: 5000 });
913
+ * try {
914
+ * await client.bazi.calculate({ ... });
915
+ * } catch (error) {
916
+ * if (error instanceof TimeoutError) {
917
+ * console.error('Request timed out after', error.timeoutMs, 'ms');
918
+ * }
919
+ * }
920
+ * ```
921
+ */
922
+ declare class TimeoutError extends BaziError {
923
+ readonly kind: BaziErrorKind;
924
+ /** The configured timeout in milliseconds. */
925
+ readonly timeoutMs: number;
926
+ constructor(timeoutMs: number);
927
+ }
928
+ /**
929
+ * Thrown when `fetch()` throws — typically caused by no internet connection,
930
+ * DNS resolution failures, or the server refusing the connection.
931
+ *
932
+ * @example
933
+ * ```typescript
934
+ * try {
935
+ * await client.bazi.calculate({ ... });
936
+ * } catch (error) {
937
+ * if (error instanceof NetworkError) {
938
+ * console.error('Network failure:', error.cause);
939
+ * }
940
+ * }
941
+ * ```
942
+ */
943
+ declare class NetworkError extends BaziError {
944
+ readonly kind: BaziErrorKind;
945
+ /** The original error thrown by `fetch()`. */
946
+ readonly cause: unknown;
947
+ constructor(cause: unknown);
948
+ }
949
+
950
+ export { API_VERSION, ApiError, BaziClient, BaziError, NetworkError, TimeoutError, ValidationError, WebhookService, verifyWebhookSignature };
951
+ export type { AdvancedPillars, Analysis, ApiKeyItem, ApiKeyListResponse, ApiResponse, AuthUser, BaziCalculateRequest, BaziCalculateResponse, BaziClientOptions, BaziErrorKind, BaziInput, ChangePasswordRequest, Constellation, CurrentAnnualLuck, EarthlyBranches, FiveElements, ForgotPasswordRequest, FourPillars, GeneratedApiKey, GodsAndStars, HeavenlyStems, HiddenStems, Interactions, LifePredictions, LiuNian, LoginRequest, LoginResponse, LuckPillarItem, LuckPillars, LunarInfo, NaYin, RefreshTokenResponse, RegisterRequest, ResetPasswordRequest, SolarInfo, SolarTerms, TenGods, UserProfile, VerifyEmailRequest, VerifySignatureOptions, Zodiac };