ani-client 1.4.4 → 1.5.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/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  > A simple, typed client to fetch anime, manga, character, staff and user data from [AniList](https://anilist.co).
8
8
 
9
- ✨ **Showcase**: [Check here](https://ani-client-docs.vercel.app/showcase) to see which projects use this package!
9
+ ✨ **Showcase**: [Check here](https://docs-aniclient.gonzyuidev.xyz/showcase) to see which projects use this package!
10
10
 
11
11
  - **Zero dependencies** — uses the native `fetch` API
12
12
  - **Universal** — Node.js ≥ 20, Bun, Deno and modern browsers
@@ -17,7 +17,7 @@
17
17
 
18
18
  The full API reference, usage guide, and configuration examples are available on our official documentation website!
19
19
 
20
- **[👉 View the full documentation here](https://ani-client-docs.vercel.app/)**
20
+ **[👉 View the full documentation here](https://docs-aniclient.gonzyuidev.xyz/)**
21
21
 
22
22
  ## Install
23
23
 
package/dist/index.d.mts CHANGED
@@ -348,27 +348,36 @@ interface Studio {
348
348
  name: string;
349
349
  isAnimationStudio: boolean;
350
350
  siteUrl: string | null;
351
- }
352
- interface StudioConnection {
353
- nodes: Studio[];
354
- }
355
- interface StudioDetail {
356
- id: number;
357
- name: string;
358
- isAnimationStudio: boolean;
359
- siteUrl: string | null;
360
- favourites: number | null;
361
- media: {
351
+ favourites?: number | null;
352
+ media?: {
362
353
  pageInfo: PageInfo;
363
354
  nodes: Pick<Media, "id" | "title" | "type" | "format" | "coverImage" | "siteUrl">[];
364
355
  } | null;
365
356
  }
357
+ interface StudioConnection {
358
+ nodes: Studio[];
359
+ }
360
+ /**
361
+ * @deprecated Use `Studio` instead. `StudioDetail` is an alias kept for backward compatibility.
362
+ */
363
+ type StudioDetail = Studio;
366
364
  interface SearchStudioOptions {
367
365
  query?: string;
368
366
  page?: number;
369
367
  perPage?: number;
370
368
  }
371
369
 
370
+ declare enum UserSort {
371
+ ID = "ID",
372
+ ID_DESC = "ID_DESC",
373
+ USERNAME = "USERNAME",
374
+ USERNAME_DESC = "USERNAME_DESC",
375
+ WATCHED_TIME = "WATCHED_TIME",
376
+ WATCHED_TIME_DESC = "WATCHED_TIME_DESC",
377
+ CHAPTERS_READ = "CHAPTERS_READ",
378
+ CHAPTERS_READ_DESC = "CHAPTERS_READ_DESC",
379
+ SEARCH_MATCH = "SEARCH_MATCH"
380
+ }
372
381
  interface UserAvatar {
373
382
  large: string | null;
374
383
  medium: string | null;
@@ -398,11 +407,34 @@ interface User {
398
407
  manga: UserStatistics;
399
408
  } | null;
400
409
  }
410
+ interface SearchUserOptions {
411
+ query?: string;
412
+ sort?: UserSort[];
413
+ page?: number;
414
+ perPage?: number;
415
+ }
401
416
 
402
417
  declare enum MediaType {
403
418
  ANIME = "ANIME",
404
419
  MANGA = "MANGA"
405
420
  }
421
+ declare enum MediaSource {
422
+ ORIGINAL = "ORIGINAL",
423
+ MANGA = "MANGA",
424
+ LIGHT_NOVEL = "LIGHT_NOVEL",
425
+ VISUAL_NOVEL = "VISUAL_NOVEL",
426
+ VIDEO_GAME = "VIDEO_GAME",
427
+ OTHER = "OTHER",
428
+ NOVEL = "NOVEL",
429
+ DOUJINSHI = "DOUJINSHI",
430
+ ANIME = "ANIME",
431
+ WEB_NOVEL = "WEB_NOVEL",
432
+ LIVE_ACTION = "LIVE_ACTION",
433
+ GAME = "GAME",
434
+ COMIC = "COMIC",
435
+ MULTIMEDIA_PROJECT = "MULTIMEDIA_PROJECT",
436
+ PICTURE_BOOK = "PICTURE_BOOK"
437
+ }
406
438
  declare enum MediaFormat {
407
439
  TV = "TV",
408
440
  TV_SHORT = "TV_SHORT",
@@ -558,6 +590,13 @@ interface MediaRecommendationNode {
558
590
  rating: number | null;
559
591
  mediaRecommendation: Pick<Media, "id" | "title" | "type" | "format" | "coverImage" | "averageScore" | "siteUrl">;
560
592
  }
593
+ interface NextAiringEpisode {
594
+ id: number;
595
+ airingAt: number;
596
+ episode: number;
597
+ mediaId: number;
598
+ timeUntilAiring: number;
599
+ }
561
600
  interface Media {
562
601
  id: number;
563
602
  idMal: number | null;
@@ -576,7 +615,7 @@ interface Media {
576
615
  volumes: number | null;
577
616
  countryOfOrigin: string | null;
578
617
  isLicensed: boolean | null;
579
- source: string | null;
618
+ source: MediaSource | null;
580
619
  hashtag: string | null;
581
620
  trailer: MediaTrailer | null;
582
621
  coverImage: MediaCoverImage;
@@ -599,6 +638,7 @@ interface Media {
599
638
  recommendations?: {
600
639
  nodes: MediaRecommendationNode[];
601
640
  };
641
+ nextAiringEpisode: NextAiringEpisode | null;
602
642
  isAdult: boolean | null;
603
643
  siteUrl: string | null;
604
644
  }
@@ -609,8 +649,18 @@ interface SearchMediaOptions {
609
649
  status?: MediaStatus;
610
650
  season?: MediaSeason;
611
651
  seasonYear?: number;
652
+ /** Single genre filter (kept for backward compat) */
612
653
  genre?: string;
654
+ /** Single tag filter (kept for backward compat) */
613
655
  tag?: string;
656
+ /** Filter by multiple genres (media must match ALL) */
657
+ genres?: string[];
658
+ /** Filter by multiple tags (media must match ALL) */
659
+ tags?: string[];
660
+ /** Exclude media with any of these genres */
661
+ genresExclude?: string[];
662
+ /** Exclude media with any of these tags */
663
+ tagsExclude?: string[];
614
664
  isAdult?: boolean;
615
665
  sort?: MediaSort[];
616
666
  page?: number;
@@ -814,6 +864,26 @@ declare class AniListClient {
814
864
  * @param perPage - Results per page (default 20, max 50)
815
865
  */
816
866
  getTrending(type?: MediaType, page?: number, perPage?: number): Promise<PagedResult<Media>>;
867
+ /**
868
+ * Get the most popular anime or manga.
869
+ *
870
+ * Convenience wrapper around `searchMedia` with `sort: POPULARITY_DESC`.
871
+ *
872
+ * @param type - `MediaType.ANIME` or `MediaType.MANGA` (defaults to ANIME)
873
+ * @param page - Page number (default 1)
874
+ * @param perPage - Results per page (default 20, max 50)
875
+ */
876
+ getPopular(type?: MediaType, page?: number, perPage?: number): Promise<PagedResult<Media>>;
877
+ /**
878
+ * Get the highest-rated anime or manga.
879
+ *
880
+ * Convenience wrapper around `searchMedia` with `sort: SCORE_DESC`.
881
+ *
882
+ * @param type - `MediaType.ANIME` or `MediaType.MANGA` (defaults to ANIME)
883
+ * @param page - Page number (default 1)
884
+ * @param perPage - Results per page (default 20, max 50)
885
+ */
886
+ getTopRated(type?: MediaType, page?: number, perPage?: number): Promise<PagedResult<Media>>;
817
887
  /**
818
888
  * Fetch a character by AniList ID.
819
889
  *
@@ -881,31 +951,39 @@ declare class AniListClient {
881
951
  */
882
952
  searchStaff(options?: SearchStaffOptions): Promise<PagedResult<Staff>>;
883
953
  /**
884
- * Fetch a user by AniList ID.
954
+ * Fetch a user by AniList ID or username.
885
955
  *
886
- * @param id - The AniList user ID
956
+ * @param idOrName - The AniList user ID (number) or username (string)
887
957
  * @returns The user object
888
958
  *
889
959
  * @example
890
960
  * ```ts
891
961
  * const user = await client.getUser(1);
962
+ * const user2 = await client.getUser("AniList");
892
963
  * console.log(user.name);
893
964
  * ```
894
965
  */
895
- getUser(id: number): Promise<User>;
966
+ getUser(idOrName: number | string): Promise<User>;
896
967
  /**
897
968
  * Fetch a user by username.
898
969
  *
970
+ * @deprecated Use `getUser(name)` instead.
899
971
  * @param name - The AniList username
900
972
  * @returns The user object
973
+ */
974
+ getUserByName(name: string): Promise<User>;
975
+ /**
976
+ * Search for users by name.
977
+ *
978
+ * @param options - Search / pagination parameters
979
+ * @returns Paginated results with matching users
901
980
  *
902
981
  * @example
903
982
  * ```ts
904
- * const user = await client.getUserByName("AniList");
905
- * console.log(user.statistics);
983
+ * const result = await client.searchUsers({ query: "AniList", perPage: 5 });
906
984
  * ```
907
985
  */
908
- getUserByName(name: string): Promise<User>;
986
+ searchUsers(options?: SearchUserOptions): Promise<PagedResult<User>>;
909
987
  /**
910
988
  * Execute an arbitrary GraphQL query against the AniList API.
911
989
  * Useful for advanced use-cases not covered by the built-in methods.
@@ -1030,7 +1108,7 @@ declare class AniListClient {
1030
1108
  *
1031
1109
  * @param id - The AniList studio ID
1032
1110
  */
1033
- getStudio(id: number): Promise<StudioDetail>;
1111
+ getStudio(id: number): Promise<Studio>;
1034
1112
  /**
1035
1113
  * Search for studios by name.
1036
1114
  *
@@ -1042,7 +1120,7 @@ declare class AniListClient {
1042
1120
  * const studios = await client.searchStudios({ query: "MAPPA" });
1043
1121
  * ```
1044
1122
  */
1045
- searchStudios(options?: SearchStudioOptions): Promise<PagedResult<StudioDetail>>;
1123
+ searchStudios(options?: SearchStudioOptions): Promise<PagedResult<Studio>>;
1046
1124
  /**
1047
1125
  * Get all available genres on AniList.
1048
1126
  *
@@ -1124,6 +1202,14 @@ declare class AniListClient {
1124
1202
  * @returns Number of entries removed
1125
1203
  */
1126
1204
  invalidateCache(pattern: string | RegExp): Promise<number>;
1205
+ /**
1206
+ * Clean up resources held by the client.
1207
+ *
1208
+ * Clears the in-memory cache and aborts any pending in-flight requests.
1209
+ * If using a custom cache adapter (e.g. Redis), call its close/disconnect
1210
+ * method separately.
1211
+ */
1212
+ destroy(): Promise<void>;
1127
1213
  }
1128
1214
 
1129
1215
  /**
@@ -1160,7 +1246,10 @@ declare class MemoryCache implements CacheAdapter {
1160
1246
  /**
1161
1247
  * Remove all entries whose key matches the given pattern.
1162
1248
  *
1163
- * @param pattern A string (converted to RegExp) or RegExp.
1249
+ * - **String**: treated as a substring match (e.g. `"Media"` removes all keys containing `"Media"`).
1250
+ * - **RegExp**: tested against each key directly.
1251
+ *
1252
+ * @param pattern — A string (substring match) or RegExp.
1164
1253
  * @returns Number of entries removed.
1165
1254
  */
1166
1255
  invalidate(pattern: string | RegExp): number;
@@ -1253,8 +1342,10 @@ declare class RateLimiter {
1253
1342
  private readonly enabled;
1254
1343
  private readonly timeoutMs;
1255
1344
  private readonly retryOnNetworkError;
1256
- /** @internal */
1257
- private timestamps;
1345
+ /** @internal — sliding window: circular buffer of timestamps */
1346
+ private readonly timestamps;
1347
+ private head;
1348
+ private count;
1258
1349
  constructor(options?: RateLimitOptions);
1259
1350
  /**
1260
1351
  * Wait until it's safe to make a request (respects rate limit window).
@@ -1262,14 +1353,17 @@ declare class RateLimiter {
1262
1353
  acquire(): Promise<void>;
1263
1354
  /**
1264
1355
  * Execute a fetch with automatic retry on 429 responses and network errors.
1356
+ * Uses exponential backoff with jitter for retry delays.
1265
1357
  */
1266
1358
  fetchWithRetry(url: string, init: RequestInit, hooks?: {
1267
1359
  onRetry?: (attempt: number, reason: string, delayMs: number) => void;
1268
1360
  onRateLimit?: (retryAfterMs: number) => void;
1269
1361
  }): Promise<Response>;
1362
+ /** @internal — Exponential backoff with jitter, capped at 30s */
1363
+ private exponentialDelay;
1270
1364
  /** @internal */
1271
1365
  private fetchWithTimeout;
1272
1366
  private sleep;
1273
1367
  }
1274
1368
 
1275
- export { type AiringSchedule, AiringSort, AniListClient, type AniListClientOptions, AniListError, type AniListHooks, type CacheAdapter, type CacheOptions, type Character, type CharacterImage, type CharacterIncludeOptions, type CharacterMediaEdge, 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 StaffIncludeOptions, type StaffMediaNode, type StaffName, StaffSort, type StatusDistribution, type StreamingEpisode, type Studio, type StudioConnection, type StudioDetail, type User, type UserAvatar, type UserStatistics, type VoiceActor };
1369
+ export { type AiringSchedule, AiringSort, AniListClient, type AniListClientOptions, AniListError, type AniListHooks, type CacheAdapter, type CacheOptions, type Character, type CharacterImage, type CharacterIncludeOptions, type CharacterMediaEdge, 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, MediaSource, type MediaStaffConnection, type MediaStaffEdge, type MediaStats, MediaStatus, type MediaTag, type MediaTitle, type MediaTrailer, MediaType, MemoryCache, type NextAiringEpisode, 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 SearchUserOptions, type Staff, type StaffImage, type StaffIncludeOptions, type StaffMediaNode, type StaffName, StaffSort, type StatusDistribution, type StreamingEpisode, type Studio, type StudioConnection, type StudioDetail, type User, type UserAvatar, UserSort, type UserStatistics, type VoiceActor };
package/dist/index.d.ts CHANGED
@@ -348,27 +348,36 @@ interface Studio {
348
348
  name: string;
349
349
  isAnimationStudio: boolean;
350
350
  siteUrl: string | null;
351
- }
352
- interface StudioConnection {
353
- nodes: Studio[];
354
- }
355
- interface StudioDetail {
356
- id: number;
357
- name: string;
358
- isAnimationStudio: boolean;
359
- siteUrl: string | null;
360
- favourites: number | null;
361
- media: {
351
+ favourites?: number | null;
352
+ media?: {
362
353
  pageInfo: PageInfo;
363
354
  nodes: Pick<Media, "id" | "title" | "type" | "format" | "coverImage" | "siteUrl">[];
364
355
  } | null;
365
356
  }
357
+ interface StudioConnection {
358
+ nodes: Studio[];
359
+ }
360
+ /**
361
+ * @deprecated Use `Studio` instead. `StudioDetail` is an alias kept for backward compatibility.
362
+ */
363
+ type StudioDetail = Studio;
366
364
  interface SearchStudioOptions {
367
365
  query?: string;
368
366
  page?: number;
369
367
  perPage?: number;
370
368
  }
371
369
 
370
+ declare enum UserSort {
371
+ ID = "ID",
372
+ ID_DESC = "ID_DESC",
373
+ USERNAME = "USERNAME",
374
+ USERNAME_DESC = "USERNAME_DESC",
375
+ WATCHED_TIME = "WATCHED_TIME",
376
+ WATCHED_TIME_DESC = "WATCHED_TIME_DESC",
377
+ CHAPTERS_READ = "CHAPTERS_READ",
378
+ CHAPTERS_READ_DESC = "CHAPTERS_READ_DESC",
379
+ SEARCH_MATCH = "SEARCH_MATCH"
380
+ }
372
381
  interface UserAvatar {
373
382
  large: string | null;
374
383
  medium: string | null;
@@ -398,11 +407,34 @@ interface User {
398
407
  manga: UserStatistics;
399
408
  } | null;
400
409
  }
410
+ interface SearchUserOptions {
411
+ query?: string;
412
+ sort?: UserSort[];
413
+ page?: number;
414
+ perPage?: number;
415
+ }
401
416
 
402
417
  declare enum MediaType {
403
418
  ANIME = "ANIME",
404
419
  MANGA = "MANGA"
405
420
  }
421
+ declare enum MediaSource {
422
+ ORIGINAL = "ORIGINAL",
423
+ MANGA = "MANGA",
424
+ LIGHT_NOVEL = "LIGHT_NOVEL",
425
+ VISUAL_NOVEL = "VISUAL_NOVEL",
426
+ VIDEO_GAME = "VIDEO_GAME",
427
+ OTHER = "OTHER",
428
+ NOVEL = "NOVEL",
429
+ DOUJINSHI = "DOUJINSHI",
430
+ ANIME = "ANIME",
431
+ WEB_NOVEL = "WEB_NOVEL",
432
+ LIVE_ACTION = "LIVE_ACTION",
433
+ GAME = "GAME",
434
+ COMIC = "COMIC",
435
+ MULTIMEDIA_PROJECT = "MULTIMEDIA_PROJECT",
436
+ PICTURE_BOOK = "PICTURE_BOOK"
437
+ }
406
438
  declare enum MediaFormat {
407
439
  TV = "TV",
408
440
  TV_SHORT = "TV_SHORT",
@@ -558,6 +590,13 @@ interface MediaRecommendationNode {
558
590
  rating: number | null;
559
591
  mediaRecommendation: Pick<Media, "id" | "title" | "type" | "format" | "coverImage" | "averageScore" | "siteUrl">;
560
592
  }
593
+ interface NextAiringEpisode {
594
+ id: number;
595
+ airingAt: number;
596
+ episode: number;
597
+ mediaId: number;
598
+ timeUntilAiring: number;
599
+ }
561
600
  interface Media {
562
601
  id: number;
563
602
  idMal: number | null;
@@ -576,7 +615,7 @@ interface Media {
576
615
  volumes: number | null;
577
616
  countryOfOrigin: string | null;
578
617
  isLicensed: boolean | null;
579
- source: string | null;
618
+ source: MediaSource | null;
580
619
  hashtag: string | null;
581
620
  trailer: MediaTrailer | null;
582
621
  coverImage: MediaCoverImage;
@@ -599,6 +638,7 @@ interface Media {
599
638
  recommendations?: {
600
639
  nodes: MediaRecommendationNode[];
601
640
  };
641
+ nextAiringEpisode: NextAiringEpisode | null;
602
642
  isAdult: boolean | null;
603
643
  siteUrl: string | null;
604
644
  }
@@ -609,8 +649,18 @@ interface SearchMediaOptions {
609
649
  status?: MediaStatus;
610
650
  season?: MediaSeason;
611
651
  seasonYear?: number;
652
+ /** Single genre filter (kept for backward compat) */
612
653
  genre?: string;
654
+ /** Single tag filter (kept for backward compat) */
613
655
  tag?: string;
656
+ /** Filter by multiple genres (media must match ALL) */
657
+ genres?: string[];
658
+ /** Filter by multiple tags (media must match ALL) */
659
+ tags?: string[];
660
+ /** Exclude media with any of these genres */
661
+ genresExclude?: string[];
662
+ /** Exclude media with any of these tags */
663
+ tagsExclude?: string[];
614
664
  isAdult?: boolean;
615
665
  sort?: MediaSort[];
616
666
  page?: number;
@@ -814,6 +864,26 @@ declare class AniListClient {
814
864
  * @param perPage - Results per page (default 20, max 50)
815
865
  */
816
866
  getTrending(type?: MediaType, page?: number, perPage?: number): Promise<PagedResult<Media>>;
867
+ /**
868
+ * Get the most popular anime or manga.
869
+ *
870
+ * Convenience wrapper around `searchMedia` with `sort: POPULARITY_DESC`.
871
+ *
872
+ * @param type - `MediaType.ANIME` or `MediaType.MANGA` (defaults to ANIME)
873
+ * @param page - Page number (default 1)
874
+ * @param perPage - Results per page (default 20, max 50)
875
+ */
876
+ getPopular(type?: MediaType, page?: number, perPage?: number): Promise<PagedResult<Media>>;
877
+ /**
878
+ * Get the highest-rated anime or manga.
879
+ *
880
+ * Convenience wrapper around `searchMedia` with `sort: SCORE_DESC`.
881
+ *
882
+ * @param type - `MediaType.ANIME` or `MediaType.MANGA` (defaults to ANIME)
883
+ * @param page - Page number (default 1)
884
+ * @param perPage - Results per page (default 20, max 50)
885
+ */
886
+ getTopRated(type?: MediaType, page?: number, perPage?: number): Promise<PagedResult<Media>>;
817
887
  /**
818
888
  * Fetch a character by AniList ID.
819
889
  *
@@ -881,31 +951,39 @@ declare class AniListClient {
881
951
  */
882
952
  searchStaff(options?: SearchStaffOptions): Promise<PagedResult<Staff>>;
883
953
  /**
884
- * Fetch a user by AniList ID.
954
+ * Fetch a user by AniList ID or username.
885
955
  *
886
- * @param id - The AniList user ID
956
+ * @param idOrName - The AniList user ID (number) or username (string)
887
957
  * @returns The user object
888
958
  *
889
959
  * @example
890
960
  * ```ts
891
961
  * const user = await client.getUser(1);
962
+ * const user2 = await client.getUser("AniList");
892
963
  * console.log(user.name);
893
964
  * ```
894
965
  */
895
- getUser(id: number): Promise<User>;
966
+ getUser(idOrName: number | string): Promise<User>;
896
967
  /**
897
968
  * Fetch a user by username.
898
969
  *
970
+ * @deprecated Use `getUser(name)` instead.
899
971
  * @param name - The AniList username
900
972
  * @returns The user object
973
+ */
974
+ getUserByName(name: string): Promise<User>;
975
+ /**
976
+ * Search for users by name.
977
+ *
978
+ * @param options - Search / pagination parameters
979
+ * @returns Paginated results with matching users
901
980
  *
902
981
  * @example
903
982
  * ```ts
904
- * const user = await client.getUserByName("AniList");
905
- * console.log(user.statistics);
983
+ * const result = await client.searchUsers({ query: "AniList", perPage: 5 });
906
984
  * ```
907
985
  */
908
- getUserByName(name: string): Promise<User>;
986
+ searchUsers(options?: SearchUserOptions): Promise<PagedResult<User>>;
909
987
  /**
910
988
  * Execute an arbitrary GraphQL query against the AniList API.
911
989
  * Useful for advanced use-cases not covered by the built-in methods.
@@ -1030,7 +1108,7 @@ declare class AniListClient {
1030
1108
  *
1031
1109
  * @param id - The AniList studio ID
1032
1110
  */
1033
- getStudio(id: number): Promise<StudioDetail>;
1111
+ getStudio(id: number): Promise<Studio>;
1034
1112
  /**
1035
1113
  * Search for studios by name.
1036
1114
  *
@@ -1042,7 +1120,7 @@ declare class AniListClient {
1042
1120
  * const studios = await client.searchStudios({ query: "MAPPA" });
1043
1121
  * ```
1044
1122
  */
1045
- searchStudios(options?: SearchStudioOptions): Promise<PagedResult<StudioDetail>>;
1123
+ searchStudios(options?: SearchStudioOptions): Promise<PagedResult<Studio>>;
1046
1124
  /**
1047
1125
  * Get all available genres on AniList.
1048
1126
  *
@@ -1124,6 +1202,14 @@ declare class AniListClient {
1124
1202
  * @returns Number of entries removed
1125
1203
  */
1126
1204
  invalidateCache(pattern: string | RegExp): Promise<number>;
1205
+ /**
1206
+ * Clean up resources held by the client.
1207
+ *
1208
+ * Clears the in-memory cache and aborts any pending in-flight requests.
1209
+ * If using a custom cache adapter (e.g. Redis), call its close/disconnect
1210
+ * method separately.
1211
+ */
1212
+ destroy(): Promise<void>;
1127
1213
  }
1128
1214
 
1129
1215
  /**
@@ -1160,7 +1246,10 @@ declare class MemoryCache implements CacheAdapter {
1160
1246
  /**
1161
1247
  * Remove all entries whose key matches the given pattern.
1162
1248
  *
1163
- * @param pattern A string (converted to RegExp) or RegExp.
1249
+ * - **String**: treated as a substring match (e.g. `"Media"` removes all keys containing `"Media"`).
1250
+ * - **RegExp**: tested against each key directly.
1251
+ *
1252
+ * @param pattern — A string (substring match) or RegExp.
1164
1253
  * @returns Number of entries removed.
1165
1254
  */
1166
1255
  invalidate(pattern: string | RegExp): number;
@@ -1253,8 +1342,10 @@ declare class RateLimiter {
1253
1342
  private readonly enabled;
1254
1343
  private readonly timeoutMs;
1255
1344
  private readonly retryOnNetworkError;
1256
- /** @internal */
1257
- private timestamps;
1345
+ /** @internal — sliding window: circular buffer of timestamps */
1346
+ private readonly timestamps;
1347
+ private head;
1348
+ private count;
1258
1349
  constructor(options?: RateLimitOptions);
1259
1350
  /**
1260
1351
  * Wait until it's safe to make a request (respects rate limit window).
@@ -1262,14 +1353,17 @@ declare class RateLimiter {
1262
1353
  acquire(): Promise<void>;
1263
1354
  /**
1264
1355
  * Execute a fetch with automatic retry on 429 responses and network errors.
1356
+ * Uses exponential backoff with jitter for retry delays.
1265
1357
  */
1266
1358
  fetchWithRetry(url: string, init: RequestInit, hooks?: {
1267
1359
  onRetry?: (attempt: number, reason: string, delayMs: number) => void;
1268
1360
  onRateLimit?: (retryAfterMs: number) => void;
1269
1361
  }): Promise<Response>;
1362
+ /** @internal — Exponential backoff with jitter, capped at 30s */
1363
+ private exponentialDelay;
1270
1364
  /** @internal */
1271
1365
  private fetchWithTimeout;
1272
1366
  private sleep;
1273
1367
  }
1274
1368
 
1275
- export { type AiringSchedule, AiringSort, AniListClient, type AniListClientOptions, AniListError, type AniListHooks, type CacheAdapter, type CacheOptions, type Character, type CharacterImage, type CharacterIncludeOptions, type CharacterMediaEdge, 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 StaffIncludeOptions, type StaffMediaNode, type StaffName, StaffSort, type StatusDistribution, type StreamingEpisode, type Studio, type StudioConnection, type StudioDetail, type User, type UserAvatar, type UserStatistics, type VoiceActor };
1369
+ export { type AiringSchedule, AiringSort, AniListClient, type AniListClientOptions, AniListError, type AniListHooks, type CacheAdapter, type CacheOptions, type Character, type CharacterImage, type CharacterIncludeOptions, type CharacterMediaEdge, 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, MediaSource, type MediaStaffConnection, type MediaStaffEdge, type MediaStats, MediaStatus, type MediaTag, type MediaTitle, type MediaTrailer, MediaType, MemoryCache, type NextAiringEpisode, 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 SearchUserOptions, type Staff, type StaffImage, type StaffIncludeOptions, type StaffMediaNode, type StaffName, StaffSort, type StatusDistribution, type StreamingEpisode, type Studio, type StudioConnection, type StudioDetail, type User, type UserAvatar, UserSort, type UserStatistics, type VoiceActor };