ani-client 1.2.0 → 1.4.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/dist/index.d.mts CHANGED
@@ -29,21 +29,37 @@ declare enum MediaSeason {
29
29
  }
30
30
  declare enum MediaSort {
31
31
  ID = "ID",
32
+ ID_DESC = "ID_DESC",
32
33
  TITLE_ROMAJI = "TITLE_ROMAJI",
34
+ TITLE_ROMAJI_DESC = "TITLE_ROMAJI_DESC",
33
35
  TITLE_ENGLISH = "TITLE_ENGLISH",
36
+ TITLE_ENGLISH_DESC = "TITLE_ENGLISH_DESC",
34
37
  TITLE_NATIVE = "TITLE_NATIVE",
38
+ TITLE_NATIVE_DESC = "TITLE_NATIVE_DESC",
35
39
  TYPE = "TYPE",
40
+ TYPE_DESC = "TYPE_DESC",
36
41
  FORMAT = "FORMAT",
42
+ FORMAT_DESC = "FORMAT_DESC",
37
43
  START_DATE = "START_DATE",
44
+ START_DATE_DESC = "START_DATE_DESC",
38
45
  END_DATE = "END_DATE",
46
+ END_DATE_DESC = "END_DATE_DESC",
39
47
  SCORE = "SCORE",
48
+ SCORE_DESC = "SCORE_DESC",
40
49
  POPULARITY = "POPULARITY",
50
+ POPULARITY_DESC = "POPULARITY_DESC",
41
51
  TRENDING = "TRENDING",
52
+ TRENDING_DESC = "TRENDING_DESC",
42
53
  EPISODES = "EPISODES",
54
+ EPISODES_DESC = "EPISODES_DESC",
43
55
  DURATION = "DURATION",
56
+ DURATION_DESC = "DURATION_DESC",
44
57
  STATUS = "STATUS",
58
+ STATUS_DESC = "STATUS_DESC",
45
59
  FAVOURITES = "FAVOURITES",
60
+ FAVOURITES_DESC = "FAVOURITES_DESC",
46
61
  UPDATED_AT = "UPDATED_AT",
62
+ UPDATED_AT_DESC = "UPDATED_AT_DESC",
47
63
  SEARCH_MATCH = "SEARCH_MATCH"
48
64
  }
49
65
  declare enum AiringSort {
@@ -58,9 +74,17 @@ declare enum AiringSort {
58
74
  }
59
75
  declare enum CharacterSort {
60
76
  ID = "ID",
77
+ ID_DESC = "ID_DESC",
61
78
  ROLE = "ROLE",
79
+ ROLE_DESC = "ROLE_DESC",
62
80
  SEARCH_MATCH = "SEARCH_MATCH",
63
- FAVOURITES = "FAVOURITES"
81
+ FAVOURITES = "FAVOURITES",
82
+ FAVOURITES_DESC = "FAVOURITES_DESC"
83
+ }
84
+ declare enum CharacterRole {
85
+ MAIN = "MAIN",
86
+ SUPPORTING = "SUPPORTING",
87
+ BACKGROUND = "BACKGROUND"
64
88
  }
65
89
  interface MediaTitle {
66
90
  romaji: string | null;
@@ -135,6 +159,51 @@ interface CharacterImage {
135
159
  large: string | null;
136
160
  medium: string | null;
137
161
  }
162
+ interface MediaCharacterEdge {
163
+ role: CharacterRole;
164
+ node: Omit<Character, "media">;
165
+ }
166
+ interface MediaCharacterConnection {
167
+ edges: MediaCharacterEdge[];
168
+ }
169
+ interface MediaStaffEdge {
170
+ role: string;
171
+ node: Staff;
172
+ }
173
+ interface MediaStaffConnection {
174
+ edges: MediaStaffEdge[];
175
+ }
176
+ interface StreamingEpisode {
177
+ title: string | null;
178
+ thumbnail: string | null;
179
+ url: string | null;
180
+ site: string | null;
181
+ }
182
+ interface ExternalLink {
183
+ id: number;
184
+ url: string | null;
185
+ site: string;
186
+ type: string | null;
187
+ icon: string | null;
188
+ color: string | null;
189
+ }
190
+ interface ScoreDistribution {
191
+ score: number;
192
+ amount: number;
193
+ }
194
+ interface StatusDistribution {
195
+ status: MediaListStatus | string;
196
+ amount: number;
197
+ }
198
+ interface MediaStats {
199
+ scoreDistribution: ScoreDistribution[];
200
+ statusDistribution: StatusDistribution[];
201
+ }
202
+ interface MediaRecommendationNode {
203
+ id: number;
204
+ rating: number | null;
205
+ mediaRecommendation: Pick<Media, "id" | "title" | "type" | "format" | "coverImage" | "averageScore" | "siteUrl">;
206
+ }
138
207
  interface Media {
139
208
  id: number;
140
209
  idMal: number | null;
@@ -168,6 +237,14 @@ interface Media {
168
237
  tags: MediaTag[];
169
238
  studios: StudioConnection;
170
239
  relations: MediaConnection | null;
240
+ characters?: MediaCharacterConnection;
241
+ staff?: MediaStaffConnection;
242
+ streamingEpisodes?: StreamingEpisode[];
243
+ externalLinks?: ExternalLink[];
244
+ stats?: MediaStats;
245
+ recommendations?: {
246
+ nodes: MediaRecommendationNode[];
247
+ };
171
248
  isAdult: boolean | null;
172
249
  siteUrl: string | null;
173
250
  }
@@ -207,7 +284,7 @@ interface Staff {
207
284
  gender: string | null;
208
285
  dateOfBirth: FuzzyDate | null;
209
286
  dateOfDeath: FuzzyDate | null;
210
- age: number | null;
287
+ age: string | null;
211
288
  yearsActive: number[];
212
289
  homeTown: string | null;
213
290
  bloodType: string | null;
@@ -280,10 +357,7 @@ interface SearchCharacterOptions {
280
357
  }
281
358
  interface SearchStaffOptions {
282
359
  query?: string;
283
- page?: number;
284
- perPage?: number;
285
- }
286
- interface PaginatedOptions {
360
+ sort?: CharacterSort[];
287
361
  page?: number;
288
362
  perPage?: number;
289
363
  }
@@ -439,33 +513,108 @@ interface SearchStudioOptions {
439
513
  page?: number;
440
514
  perPage?: number;
441
515
  }
516
+ /**
517
+ * Options to include additional related data when fetching a media entry.
518
+ * Pass `true` to include with defaults, or an object to customize.
519
+ */
520
+ interface MediaIncludeOptions {
521
+ /** Include characters with their roles (MAIN, SUPPORTING, BACKGROUND).
522
+ * `true` = 25 results sorted by role. Object form to customize. */
523
+ characters?: boolean | {
524
+ perPage?: number;
525
+ sort?: boolean;
526
+ };
527
+ /** Include staff members with their roles.
528
+ * `true` = 25 results sorted by relevance. Object form to customize. */
529
+ staff?: boolean | {
530
+ perPage?: number;
531
+ sort?: boolean;
532
+ };
533
+ /** Include relations (default: `true` for backward compat). Set to `false` to exclude. */
534
+ relations?: boolean;
535
+ /** Include streaming episode links (Crunchyroll, Funimation, etc.) */
536
+ streamingEpisodes?: boolean;
537
+ /** Include external links (MAL, official site, etc.) */
538
+ externalLinks?: boolean;
539
+ /** Include score & status distribution stats */
540
+ stats?: boolean;
541
+ /** Include user recommendations. `true` = 10 results, or customize with `{ perPage }`. */
542
+ recommendations?: boolean | {
543
+ perPage?: number;
544
+ };
545
+ }
546
+ /**
547
+ * Interface that all cache adapters must implement.
548
+ * Methods may return sync values or Promises — the client awaits all calls.
549
+ */
550
+ interface CacheAdapter {
551
+ /** Retrieve a cached value, or `undefined` if missing / expired. */
552
+ get<T>(key: string): T | undefined | Promise<T | undefined>;
553
+ /** Store a value in the cache. */
554
+ set<T>(key: string, data: T): void | Promise<void>;
555
+ /** Remove a specific entry. Returns `true` if the key existed. */
556
+ delete(key: string): boolean | Promise<boolean>;
557
+ /** Clear the entire cache. */
558
+ clear(): void | Promise<void>;
559
+ /** Number of entries currently stored (sync). Returns -1 if unknown. */
560
+ readonly size: number;
561
+ /** Return all cache keys. */
562
+ keys(): string[] | Promise<string[]>;
563
+ /** Bulk-remove entries matching a pattern. Optional — the client provides a fallback. */
564
+ invalidate?(pattern: string | RegExp): number | Promise<number>;
565
+ }
566
+ /** Cache configuration options. */
567
+ interface CacheOptions {
568
+ /** Time-to-live in milliseconds (default: 86 400 000 = 24h) */
569
+ ttl?: number;
570
+ /** Maximum number of cached entries (default: 500, 0 = unlimited) */
571
+ maxSize?: number;
572
+ /** Set to false to disable caching entirely */
573
+ enabled?: boolean;
574
+ }
575
+ /** Rate limiter configuration options. */
576
+ interface RateLimitOptions {
577
+ /** Max requests per window (default: 85) */
578
+ maxRequests?: number;
579
+ /** Window size in ms (default: 60 000) */
580
+ windowMs?: number;
581
+ /** Max retries on 429 (default: 3) */
582
+ maxRetries?: number;
583
+ /** Retry delay in ms when Retry-After header is absent (default: 2000) */
584
+ retryDelayMs?: number;
585
+ /** Set to false to disable rate limiting entirely */
586
+ enabled?: boolean;
587
+ /** Timeout per request in ms (default: 30 000). 0 = no timeout. */
588
+ timeoutMs?: number;
589
+ /** Retry on network errors like ECONNRESET / ETIMEDOUT (default: true) */
590
+ retryOnNetworkError?: boolean;
591
+ }
592
+ /** Event hooks for logging, debugging, and monitoring. */
593
+ interface AniListHooks {
594
+ /** Called before every API request. */
595
+ onRequest?: (query: string, variables: Record<string, unknown>) => void;
596
+ /** Called when a response is served from cache. */
597
+ onCacheHit?: (key: string) => void;
598
+ /** Called when the rate limiter enforces a wait (429 received). */
599
+ onRateLimit?: (retryAfterMs: number) => void;
600
+ /** Called when a request is retried (429 or network error). */
601
+ onRetry?: (attempt: number, reason: string, delayMs: number) => void;
602
+ /** Called when a request completes. */
603
+ onResponse?: (query: string, durationMs: number, fromCache: boolean) => void;
604
+ }
442
605
  interface AniListClientOptions {
443
606
  /** Optional AniList OAuth token for authenticated requests */
444
607
  token?: string;
445
608
  /** Custom API endpoint (defaults to https://graphql.anilist.co) */
446
609
  apiUrl?: string;
447
610
  /** Cache configuration (enabled by default, 24h TTL) */
448
- cache?: {
449
- /** Time-to-live in milliseconds (default: 86 400 000 = 24h) */
450
- ttl?: number;
451
- /** Maximum number of cached entries (default: 500, 0 = unlimited) */
452
- maxSize?: number;
453
- /** Set to false to disable caching entirely */
454
- enabled?: boolean;
455
- };
611
+ cache?: CacheOptions;
612
+ /** Custom cache adapter (e.g. RedisCache). Takes precedence over `cache`. */
613
+ cacheAdapter?: CacheAdapter;
456
614
  /** Rate limiter configuration (enabled by default, 85 req/min) */
457
- rateLimit?: {
458
- /** Max requests per window (default: 85) */
459
- maxRequests?: number;
460
- /** Window size in ms (default: 60 000) */
461
- windowMs?: number;
462
- /** Max retries on 429 (default: 3) */
463
- maxRetries?: number;
464
- /** Retry delay in ms when Retry-After header is absent (default: 2000) */
465
- retryDelayMs?: number;
466
- /** Set to false to disable rate limiting entirely */
467
- enabled?: boolean;
468
- };
615
+ rateLimit?: RateLimitOptions;
616
+ /** Event hooks for logging, debugging, and monitoring */
617
+ hooks?: AniListHooks;
469
618
  }
470
619
 
471
620
  /**
@@ -489,20 +638,60 @@ interface AniListClientOptions {
489
638
  declare class AniListClient {
490
639
  private readonly apiUrl;
491
640
  private readonly headers;
492
- private readonly cache;
641
+ private readonly cacheAdapter;
493
642
  private readonly rateLimiter;
643
+ private readonly hooks;
644
+ private readonly inFlight;
494
645
  constructor(options?: AniListClientOptions);
495
646
  /**
496
647
  * @internal
497
648
  */
498
649
  private request;
650
+ /** @internal */
651
+ private executeRequest;
652
+ /**
653
+ * @internal
654
+ * Shorthand for paginated queries that follow the `Page { pageInfo, <field>[] }` pattern.
655
+ */
656
+ private pagedRequest;
657
+ /**
658
+ * @internal
659
+ * Clamp perPage to AniList's maximum of 50.
660
+ */
661
+ private clampPerPage;
499
662
  /**
500
663
  * Fetch a single media entry by its AniList ID.
501
664
  *
665
+ * Optionally include related data (characters, staff, relations, etc.) via the `include` parameter.
666
+ *
502
667
  * @param id - The AniList media ID
668
+ * @param include - Optional related data to include
503
669
  * @returns The media object
670
+ *
671
+ * @example
672
+ * ```ts
673
+ * // Basic usage — same as before (includes relations by default)
674
+ * const anime = await client.getMedia(1);
675
+ *
676
+ * // Include characters sorted by role, 25 results
677
+ * const anime = await client.getMedia(1, { characters: true });
678
+ *
679
+ * // Full control
680
+ * const anime = await client.getMedia(1, {
681
+ * characters: { perPage: 50, sort: true },
682
+ * staff: true,
683
+ * relations: true,
684
+ * streamingEpisodes: true,
685
+ * externalLinks: true,
686
+ * stats: true,
687
+ * recommendations: { perPage: 5 },
688
+ * });
689
+ *
690
+ * // Exclude relations for a lighter response
691
+ * const anime = await client.getMedia(1, { characters: true, relations: false });
692
+ * ```
504
693
  */
505
- getMedia(id: number): Promise<Media>;
694
+ getMedia(id: number, include?: MediaIncludeOptions): Promise<Media>;
506
695
  /**
507
696
  * Search for anime or manga.
508
697
  *
@@ -529,26 +718,78 @@ declare class AniListClient {
529
718
  getTrending(type?: MediaType, page?: number, perPage?: number): Promise<PagedResult<Media>>;
530
719
  /**
531
720
  * Fetch a character by AniList ID.
721
+ *
722
+ * @param id - The AniList character ID
723
+ * @returns The character object
724
+ *
725
+ * @example
726
+ * ```ts
727
+ * const spike = await client.getCharacter(1);
728
+ * console.log(spike.name.full); // "Spike Spiegel"
729
+ * ```
532
730
  */
533
731
  getCharacter(id: number): Promise<Character>;
534
732
  /**
535
733
  * Search for characters by name.
734
+ *
735
+ * @param options - Search / pagination parameters
736
+ * @returns Paginated results with matching characters
737
+ *
738
+ * @example
739
+ * ```ts
740
+ * const result = await client.searchCharacters({ query: "Luffy", perPage: 5 });
741
+ * ```
536
742
  */
537
743
  searchCharacters(options?: SearchCharacterOptions): Promise<PagedResult<Character>>;
538
744
  /**
539
745
  * Fetch a staff member by AniList ID.
746
+ *
747
+ * @param id - The AniList staff ID
748
+ * @returns The staff object
749
+ *
750
+ * @example
751
+ * ```ts
752
+ * const staff = await client.getStaff(95001);
753
+ * console.log(staff.name.full);
754
+ * ```
540
755
  */
541
756
  getStaff(id: number): Promise<Staff>;
542
757
  /**
543
758
  * Search for staff (voice actors, directors, etc.).
759
+ *
760
+ * @param options - Search / pagination parameters
761
+ * @returns Paginated results with matching staff
762
+ *
763
+ * @example
764
+ * ```ts
765
+ * const result = await client.searchStaff({ query: "Miyazaki", perPage: 5 });
766
+ * ```
544
767
  */
545
768
  searchStaff(options?: SearchStaffOptions): Promise<PagedResult<Staff>>;
546
769
  /**
547
770
  * Fetch a user by AniList ID.
771
+ *
772
+ * @param id - The AniList user ID
773
+ * @returns The user object
774
+ *
775
+ * @example
776
+ * ```ts
777
+ * const user = await client.getUser(1);
778
+ * console.log(user.name);
779
+ * ```
548
780
  */
549
781
  getUser(id: number): Promise<User>;
550
782
  /**
551
783
  * Fetch a user by username.
784
+ *
785
+ * @param name - The AniList username
786
+ * @returns The user object
787
+ *
788
+ * @example
789
+ * ```ts
790
+ * const user = await client.getUserByName("AniList");
791
+ * console.log(user.statistics);
792
+ * ```
552
793
  */
553
794
  getUserByName(name: string): Promise<User>;
554
795
  /**
@@ -729,14 +970,48 @@ declare class AniListClient {
729
970
  * ```
730
971
  */
731
972
  paginate<T>(fetchPage: (page: number) => Promise<PagedResult<T>>, maxPages?: number): AsyncGenerator<T, void, undefined>;
973
+ /**
974
+ * Fetch multiple media entries in a single API request.
975
+ * Uses GraphQL aliases to batch up to 50 IDs per call.
976
+ *
977
+ * @param ids - Array of AniList media IDs
978
+ * @returns Array of media objects (same order as input IDs)
979
+ */
980
+ getMediaBatch(ids: number[]): Promise<Media[]>;
981
+ /**
982
+ * Fetch multiple characters in a single API request.
983
+ *
984
+ * @param ids - Array of AniList character IDs
985
+ * @returns Array of character objects (same order as input IDs)
986
+ */
987
+ getCharacterBatch(ids: number[]): Promise<Character[]>;
988
+ /**
989
+ * Fetch multiple staff members in a single API request.
990
+ *
991
+ * @param ids - Array of AniList staff IDs
992
+ * @returns Array of staff objects (same order as input IDs)
993
+ */
994
+ getStaffBatch(ids: number[]): Promise<Staff[]>;
995
+ /** @internal */
996
+ private executeBatch;
997
+ /** @internal */
998
+ private chunk;
732
999
  /**
733
1000
  * Clear the entire response cache.
734
1001
  */
735
- clearCache(): void;
1002
+ clearCache(): Promise<void>;
736
1003
  /**
737
- * Number of entries currently in the cache.
1004
+ * Number of entries currently in the cache (sync).
1005
+ * For async adapters like Redis, this may be approximate.
738
1006
  */
739
1007
  get cacheSize(): number;
1008
+ /**
1009
+ * Remove cache entries whose key matches the given pattern.
1010
+ *
1011
+ * @param pattern — A string (converted to RegExp) or RegExp
1012
+ * @returns Number of entries removed
1013
+ */
1014
+ invalidateCache(pattern: string | RegExp): Promise<number>;
740
1015
  }
741
1016
 
742
1017
  /**
@@ -750,19 +1025,7 @@ declare class AniListError extends Error {
750
1025
  constructor(message: string, status: number, errors?: unknown[]);
751
1026
  }
752
1027
 
753
- /**
754
- * Simple in-memory cache with configurable TTL.
755
- * Used internally by AniListClient to avoid redundant API calls.
756
- */
757
- interface CacheOptions {
758
- /** Time-to-live in milliseconds (default: 24 hours) */
759
- ttl?: number;
760
- /** Maximum number of entries to keep (default: 500, 0 = unlimited) */
761
- maxSize?: number;
762
- /** Disable caching entirely (default: false) */
763
- enabled?: boolean;
764
- }
765
- declare class MemoryCache {
1028
+ declare class MemoryCache implements CacheAdapter {
766
1029
  private readonly ttl;
767
1030
  private readonly maxSize;
768
1031
  private readonly enabled;
@@ -780,6 +1043,87 @@ declare class MemoryCache {
780
1043
  clear(): void;
781
1044
  /** Number of entries currently stored. */
782
1045
  get size(): number;
1046
+ /** Return all cache keys. */
1047
+ keys(): string[];
1048
+ /**
1049
+ * Remove all entries whose key matches the given pattern.
1050
+ *
1051
+ * @param pattern — A string (converted to RegExp) or RegExp.
1052
+ * @returns Number of entries removed.
1053
+ */
1054
+ invalidate(pattern: string | RegExp): number;
1055
+ }
1056
+
1057
+ /**
1058
+ * Minimal interface representing a Redis client.
1059
+ * Compatible with both `ioredis` and `redis` (node-redis v4+).
1060
+ */
1061
+ interface RedisLikeClient {
1062
+ get(key: string): Promise<string | null>;
1063
+ set(key: string, value: string, ...args: unknown[]): Promise<unknown>;
1064
+ del(...keys: (string | string[])[]): Promise<number>;
1065
+ keys(pattern: string): Promise<string[]>;
1066
+ /** Optional SCAN-based iteration — used when available to avoid blocking the server. */
1067
+ scanIterator?(options: {
1068
+ MATCH: string;
1069
+ COUNT?: number;
1070
+ }): AsyncIterable<string>;
1071
+ }
1072
+ interface RedisCacheOptions {
1073
+ /** A Redis client instance (ioredis or node-redis). */
1074
+ client: RedisLikeClient;
1075
+ /** Key prefix to namespace ani-client entries (default: `"ani:"`) */
1076
+ prefix?: string;
1077
+ /** TTL in seconds (default: 86 400 = 24 h) */
1078
+ ttl?: number;
1079
+ }
1080
+ /**
1081
+ * Redis-backed cache adapter for AniListClient.
1082
+ *
1083
+ * @example
1084
+ * ```ts
1085
+ * import Redis from "ioredis";
1086
+ * import { AniListClient, RedisCache } from "ani-client";
1087
+ *
1088
+ * const redis = new Redis();
1089
+ * const client = new AniListClient({
1090
+ * cacheAdapter: new RedisCache({ client: redis }),
1091
+ * });
1092
+ * ```
1093
+ */
1094
+ declare class RedisCache implements CacheAdapter {
1095
+ private readonly client;
1096
+ private readonly prefix;
1097
+ private readonly ttl;
1098
+ constructor(options: RedisCacheOptions);
1099
+ private prefixedKey;
1100
+ get<T>(key: string): Promise<T | undefined>;
1101
+ set<T>(key: string, data: T): Promise<void>;
1102
+ delete(key: string): Promise<boolean>;
1103
+ /**
1104
+ * Collect keys matching a pattern. Uses SCAN when available, falls back to KEYS.
1105
+ *
1106
+ * **Warning:** The `KEYS` fallback is O(N) and blocks the Redis server.
1107
+ * Provide a client with `scanIterator` support for production use.
1108
+ * @internal
1109
+ */
1110
+ private collectKeys;
1111
+ clear(): Promise<void>;
1112
+ /**
1113
+ * Returns -1 because Redis keys can expire silently via TTL.
1114
+ * Use `getSize()` for an accurate count.
1115
+ */
1116
+ get size(): number;
1117
+ /** Get the actual number of keys with this prefix in Redis. */
1118
+ getSize(): Promise<number>;
1119
+ keys(): Promise<string[]>;
1120
+ /**
1121
+ * Remove all entries whose key matches the given glob pattern.
1122
+ *
1123
+ * @param pattern — A glob pattern (e.g. `"*Media*"`)
1124
+ * @returns Number of entries removed.
1125
+ */
1126
+ invalidate(pattern: string | RegExp): Promise<number>;
783
1127
  }
784
1128
 
785
1129
  /**
@@ -789,24 +1133,15 @@ declare class MemoryCache {
789
1133
  * When a 429 (Too Many Requests) is received, the client
790
1134
  * waits for the Retry-After header and retries automatically.
791
1135
  */
792
- interface RateLimitOptions {
793
- /** Max requests per window (default: 85, conservative under AniList's 90/min) */
794
- maxRequests?: number;
795
- /** Window size in milliseconds (default: 60 000 = 1 minute) */
796
- windowMs?: number;
797
- /** Max number of retries on 429 responses (default: 3) */
798
- maxRetries?: number;
799
- /** Default retry delay in ms when Retry-After header is missing (default: 2000) */
800
- retryDelayMs?: number;
801
- /** Disable rate limiting entirely (default: false) */
802
- enabled?: boolean;
803
- }
1136
+
804
1137
  declare class RateLimiter {
805
1138
  private readonly maxRequests;
806
1139
  private readonly windowMs;
807
1140
  private readonly maxRetries;
808
1141
  private readonly retryDelayMs;
809
1142
  private readonly enabled;
1143
+ private readonly timeoutMs;
1144
+ private readonly retryOnNetworkError;
810
1145
  /** @internal */
811
1146
  private timestamps;
812
1147
  constructor(options?: RateLimitOptions);
@@ -815,10 +1150,15 @@ declare class RateLimiter {
815
1150
  */
816
1151
  acquire(): Promise<void>;
817
1152
  /**
818
- * Execute a fetch with automatic retry on 429 responses.
1153
+ * Execute a fetch with automatic retry on 429 responses and network errors.
819
1154
  */
820
- fetchWithRetry(url: string, init: RequestInit): Promise<Response>;
1155
+ fetchWithRetry(url: string, init: RequestInit, hooks?: {
1156
+ onRetry?: (attempt: number, reason: string, delayMs: number) => void;
1157
+ onRateLimit?: (retryAfterMs: number) => void;
1158
+ }): Promise<Response>;
1159
+ /** @internal */
1160
+ private fetchWithTimeout;
821
1161
  private sleep;
822
1162
  }
823
1163
 
824
- export { type AiringSchedule, AiringSort, AniListClient, type AniListClientOptions, AniListError, type CacheOptions, type Character, type CharacterImage, type CharacterName, CharacterSort, type FuzzyDate, type GetAiringOptions, type GetPlanningOptions, type GetRecentChaptersOptions, type GetRecommendationsOptions, type GetSeasonOptions, type GetUserMediaListOptions, type Media, type MediaConnection, type MediaCoverImage, type MediaEdge, MediaFormat, type MediaListEntry, MediaListSort, MediaListStatus, MediaRelationType, MediaSeason, MediaSort, MediaStatus, type MediaTag, type MediaTitle, type MediaTrailer, MediaType, MemoryCache, type PageInfo, type PagedResult, type PaginatedOptions, type RateLimitOptions, RateLimiter, type Recommendation, RecommendationSort, type SearchCharacterOptions, type SearchMediaOptions, type SearchStaffOptions, type SearchStudioOptions, type Staff, type StaffImage, type StaffName, type Studio, type StudioConnection, type StudioDetail, type User, type UserAvatar, type UserStatistics };
1164
+ export { type AiringSchedule, AiringSort, AniListClient, type AniListClientOptions, AniListError, type AniListHooks, type CacheAdapter, type CacheOptions, type Character, type CharacterImage, type CharacterName, CharacterRole, CharacterSort, type ExternalLink, type FuzzyDate, type GetAiringOptions, type GetPlanningOptions, type GetRecentChaptersOptions, type GetRecommendationsOptions, type GetSeasonOptions, type GetUserMediaListOptions, type Media, type MediaCharacterConnection, type MediaCharacterEdge, type MediaConnection, type MediaCoverImage, type MediaEdge, MediaFormat, type MediaIncludeOptions, type MediaListEntry, MediaListSort, MediaListStatus, type MediaRecommendationNode, MediaRelationType, MediaSeason, MediaSort, type MediaStaffConnection, type MediaStaffEdge, type MediaStats, MediaStatus, type MediaTag, type MediaTitle, type MediaTrailer, MediaType, MemoryCache, type PageInfo, type PagedResult, type RateLimitOptions, RateLimiter, type Recommendation, RecommendationSort, RedisCache, type RedisCacheOptions, type RedisLikeClient, type ScoreDistribution, type SearchCharacterOptions, type SearchMediaOptions, type SearchStaffOptions, type SearchStudioOptions, type Staff, type StaffImage, type StaffName, type StatusDistribution, type StreamingEpisode, type Studio, type StudioConnection, type StudioDetail, type User, type UserAvatar, type UserStatistics };