ani-client 1.5.0 → 1.6.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
@@ -67,6 +67,16 @@ interface RateLimitOptions {
67
67
  timeoutMs?: number;
68
68
  /** Retry on network errors like ECONNRESET / ETIMEDOUT (default: true) */
69
69
  retryOnNetworkError?: boolean;
70
+ /**
71
+ * Custom retry delay strategy. Receives the attempt number (0-based) and the base delay,
72
+ * and should return the delay in ms before retrying.
73
+ * When omitted, the default exponential backoff with jitter is used.
74
+ *
75
+ * @example
76
+ * // Linear backoff: 1s, 2s, 3s, ...
77
+ * retryStrategy: (attempt) => (attempt + 1) * 1000
78
+ */
79
+ retryStrategy?: (attempt: number, baseDelayMs: number) => number;
70
80
  }
71
81
  /** Event hooks for logging, debugging, and monitoring. */
72
82
  interface AniListHooks {
@@ -79,7 +89,25 @@ interface AniListHooks {
79
89
  /** Called when a request is retried (429 or network error). */
80
90
  onRetry?: (attempt: number, reason: string, delayMs: number) => void;
81
91
  /** Called when a request completes. */
82
- onResponse?: (query: string, durationMs: number, fromCache: boolean) => void;
92
+ onResponse?: (query: string, durationMs: number, fromCache: boolean, rateLimitInfo?: RateLimitInfo) => void;
93
+ }
94
+ /** Rate limit information parsed from AniList API response headers. */
95
+ interface RateLimitInfo {
96
+ /** Maximum number of requests allowed per window. */
97
+ limit: number;
98
+ /** Remaining requests in the current window. */
99
+ remaining: number;
100
+ /** UNIX timestamp (seconds) when the rate limit window resets. */
101
+ reset: number;
102
+ }
103
+ /** Metadata about the last request, useful for debugging and monitoring. */
104
+ interface ResponseMeta {
105
+ /** Duration of the request in milliseconds. */
106
+ durationMs: number;
107
+ /** Whether the response was served from cache. */
108
+ fromCache: boolean;
109
+ /** Rate limit information from the API response headers (not present for cached responses). */
110
+ rateLimitInfo?: RateLimitInfo;
83
111
  }
84
112
  interface AniListClientOptions {
85
113
  /** Optional AniList OAuth token for authenticated requests */
@@ -94,6 +122,8 @@ interface AniListClientOptions {
94
122
  rateLimit?: RateLimitOptions;
95
123
  /** Event hooks for logging, debugging, and monitoring */
96
124
  hooks?: AniListHooks;
125
+ /** Optional AbortSignal to cancel all requests made by this client */
126
+ signal?: AbortSignal;
97
127
  }
98
128
 
99
129
  declare enum StaffSort {
@@ -357,10 +387,6 @@ interface Studio {
357
387
  interface StudioConnection {
358
388
  nodes: Studio[];
359
389
  }
360
- /**
361
- * @deprecated Use `Studio` instead. `StudioDetail` is an alias kept for backward compatibility.
362
- */
363
- type StudioDetail = Studio;
364
390
  interface SearchStudioOptions {
365
391
  query?: string;
366
392
  page?: number;
@@ -413,6 +439,58 @@ interface SearchUserOptions {
413
439
  page?: number;
414
440
  perPage?: number;
415
441
  }
442
+ interface FavoriteMediaNode {
443
+ id: number;
444
+ title: {
445
+ romaji: string | null;
446
+ english: string | null;
447
+ native: string | null;
448
+ userPreferred: string | null;
449
+ };
450
+ coverImage: {
451
+ large: string | null;
452
+ medium: string | null;
453
+ };
454
+ type: string | null;
455
+ format: string | null;
456
+ siteUrl: string | null;
457
+ }
458
+ interface FavoriteCharacterNode {
459
+ id: number;
460
+ name: {
461
+ full: string | null;
462
+ native: string | null;
463
+ };
464
+ image: {
465
+ large: string | null;
466
+ medium: string | null;
467
+ };
468
+ siteUrl: string | null;
469
+ }
470
+ interface FavoriteStaffNode {
471
+ id: number;
472
+ name: {
473
+ full: string | null;
474
+ native: string | null;
475
+ };
476
+ image: {
477
+ large: string | null;
478
+ medium: string | null;
479
+ };
480
+ siteUrl: string | null;
481
+ }
482
+ interface FavoriteStudioNode {
483
+ id: number;
484
+ name: string;
485
+ siteUrl: string | null;
486
+ }
487
+ interface UserFavorites {
488
+ anime: FavoriteMediaNode[];
489
+ manga: FavoriteMediaNode[];
490
+ characters: FavoriteCharacterNode[];
491
+ staff: FavoriteStaffNode[];
492
+ studios: FavoriteStudioNode[];
493
+ }
416
494
 
417
495
  declare enum MediaType {
418
496
  ANIME = "ANIME",
@@ -766,6 +844,96 @@ interface AiringSchedule {
766
844
  mediaId: number;
767
845
  media: Media;
768
846
  }
847
+ type DayOfWeek = "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday" | "Sunday";
848
+ type WeeklySchedule = Record<DayOfWeek, AiringSchedule[]>;
849
+
850
+ /** Represents a forum thread on AniList. */
851
+ interface Thread {
852
+ id: number;
853
+ title: string;
854
+ body: string | null;
855
+ userId: number;
856
+ replyUserId: number | null;
857
+ replyCommentId: number | null;
858
+ replyCount: number;
859
+ viewCount: number;
860
+ isLocked: boolean;
861
+ isSticky: boolean;
862
+ isSubscribed: boolean;
863
+ repliedAt: number | null;
864
+ createdAt: number;
865
+ updatedAt: number;
866
+ siteUrl: string | null;
867
+ user: {
868
+ id: number;
869
+ name: string;
870
+ avatar: UserAvatar;
871
+ } | null;
872
+ replyUser: {
873
+ id: number;
874
+ name: string;
875
+ avatar: UserAvatar;
876
+ } | null;
877
+ categories: ThreadCategory[] | null;
878
+ mediaCategories: ThreadMediaCategory[] | null;
879
+ likes: {
880
+ id: number;
881
+ name: string;
882
+ }[] | null;
883
+ }
884
+ interface ThreadCategory {
885
+ id: number;
886
+ name: string;
887
+ }
888
+ interface ThreadMediaCategory {
889
+ id: number;
890
+ title: {
891
+ romaji: string | null;
892
+ english: string | null;
893
+ native: string | null;
894
+ userPreferred: string | null;
895
+ };
896
+ type: string;
897
+ coverImage: {
898
+ large: string | null;
899
+ medium: string | null;
900
+ } | null;
901
+ siteUrl: string | null;
902
+ }
903
+ /** Sort options for thread queries. */
904
+ declare enum ThreadSort {
905
+ ID = "ID",
906
+ ID_DESC = "ID_DESC",
907
+ TITLE = "TITLE",
908
+ TITLE_DESC = "TITLE_DESC",
909
+ CREATED_AT = "CREATED_AT",
910
+ CREATED_AT_DESC = "CREATED_AT_DESC",
911
+ UPDATED_AT = "UPDATED_AT",
912
+ UPDATED_AT_DESC = "UPDATED_AT_DESC",
913
+ REPLIED_AT = "REPLIED_AT",
914
+ REPLIED_AT_DESC = "REPLIED_AT_DESC",
915
+ REPLY_COUNT = "REPLY_COUNT",
916
+ REPLY_COUNT_DESC = "REPLY_COUNT_DESC",
917
+ VIEW_COUNT = "VIEW_COUNT",
918
+ VIEW_COUNT_DESC = "VIEW_COUNT_DESC",
919
+ IS_STICKY = "IS_STICKY",
920
+ SEARCH_MATCH = "SEARCH_MATCH"
921
+ }
922
+ /** Options for searching/listing threads. */
923
+ interface SearchThreadOptions {
924
+ /** Search query */
925
+ query?: string;
926
+ /** Filter by media ID */
927
+ mediaId?: number;
928
+ /** Filter by category ID */
929
+ categoryId?: number;
930
+ /** Sort order */
931
+ sort?: ThreadSort[];
932
+ /** Page number */
933
+ page?: number;
934
+ /** Results per page (max 50) */
935
+ perPage?: number;
936
+ }
769
937
 
770
938
  /**
771
939
  * Lightweight AniList GraphQL client with built-in caching and rate limiting.
@@ -775,7 +943,7 @@ interface AiringSchedule {
775
943
  * import { AniListClient } from "ani-client";
776
944
  *
777
945
  * const client = new AniListClient();
778
- * const anime = await client.getMedia(1); // Cowboy Bebop
946
+ * const anime = await client.getMedia(1);
779
947
  * console.log(anime.title.romaji);
780
948
  *
781
949
  * // Custom cache & rate limit options
@@ -791,19 +959,27 @@ declare class AniListClient {
791
959
  private readonly cacheAdapter;
792
960
  private readonly rateLimiter;
793
961
  private readonly hooks;
962
+ private readonly signal?;
794
963
  private readonly inFlight;
964
+ private _rateLimitInfo?;
965
+ private _lastRequestMeta?;
795
966
  constructor(options?: AniListClientOptions);
796
967
  /**
797
- * @internal
968
+ * The current rate limit information from the last API response.
969
+ * Updated after every non-cached request.
798
970
  */
799
- private request;
800
- /** @internal */
801
- private executeRequest;
971
+ get rateLimitInfo(): RateLimitInfo | undefined;
802
972
  /**
803
- * @internal
804
- * Shorthand for paginated queries that follow the `Page { pageInfo, <field>[] }` pattern.
973
+ * Metadata about the last request (duration, cache status, rate limit info).
974
+ * Useful for debugging and monitoring.
805
975
  */
806
- private pagedRequest;
976
+ get lastRequestMeta(): ResponseMeta | undefined;
977
+ /** @internal */
978
+ request<T>(query: string, variables?: Record<string, unknown>): Promise<T>;
979
+ /** @internal */
980
+ private executeRequest;
981
+ /** @internal */
982
+ pagedRequest<T>(query: string, variables: Record<string, unknown>, field: string): Promise<PagedResult<T>>;
807
983
  /**
808
984
  * Fetch a single media entry by its AniList ID.
809
985
  *
@@ -811,33 +987,6 @@ declare class AniListClient {
811
987
  *
812
988
  * @param id - The AniList media ID
813
989
  * @param include - Optional related data to include
814
- * @returns The media object
815
- *
816
- * @example
817
- * ```ts
818
- * // Basic usage — same as before (includes relations by default)
819
- * const anime = await client.getMedia(1);
820
- *
821
- * // Include characters sorted by role, 25 results
822
- * const anime = await client.getMedia(1, { characters: true });
823
- *
824
- * // Include characters with voice actors
825
- * const anime = await client.getMedia(1, { characters: { voiceActors: true } });
826
- *
827
- * // Full control
828
- * const anime = await client.getMedia(1, {
829
- * characters: { perPage: 50, sort: true },
830
- * staff: true,
831
- * relations: true,
832
- * streamingEpisodes: true,
833
- * externalLinks: true,
834
- * stats: true,
835
- * recommendations: { perPage: 5 },
836
- * });
837
- *
838
- * // Exclude relations for a lighter response
839
- * const anime = await client.getMedia(1, { characters: true, relations: false });
840
- * ```
841
990
  */
842
991
  getMedia(id: number, include?: MediaIncludeOptions): Promise<Media>;
843
992
  /**
@@ -845,370 +994,93 @@ declare class AniListClient {
845
994
  *
846
995
  * @param options - Search / filter parameters
847
996
  * @returns Paginated results with matching media
848
- *
849
- * @example
850
- * ```ts
851
- * const results = await client.searchMedia({
852
- * query: "Naruto",
853
- * type: MediaType.ANIME,
854
- * perPage: 5,
855
- * });
856
- * ```
857
997
  */
858
998
  searchMedia(options?: SearchMediaOptions): Promise<PagedResult<Media>>;
859
- /**
860
- * Get currently trending anime or manga.
861
- *
862
- * @param type - `MediaType.ANIME` or `MediaType.MANGA` (defaults to ANIME)
863
- * @param page - Page number (default 1)
864
- * @param perPage - Results per page (default 20, max 50)
865
- */
999
+ /** Get currently trending anime or manga. */
866
1000
  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
- */
1001
+ /** Get the most popular anime or manga. */
876
1002
  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
- */
1003
+ /** Get the highest-rated anime or manga. */
886
1004
  getTopRated(type?: MediaType, page?: number, perPage?: number): Promise<PagedResult<Media>>;
887
- /**
888
- * Fetch a character by AniList ID.
889
- *
890
- * @param id - The AniList character ID
891
- * @param include - Optional include options (e.g. voice actors)
892
- * @returns The character object
893
- *
894
- * @example
895
- * ```ts
896
- * const spike = await client.getCharacter(1);
897
- * console.log(spike.name.full); // "Spike Spiegel"
898
- *
899
- * // With voice actors
900
- * const spike = await client.getCharacter(1, { voiceActors: true });
901
- * spike.media?.edges?.forEach((e) => {
902
- * console.log(e.node.title.romaji);
903
- * e.voiceActors?.forEach((va) => console.log(` VA: ${va.name.full}`));
904
- * });
905
- * ```
906
- */
1005
+ /** Get recently aired anime episodes. */
1006
+ getAiredEpisodes(options?: GetAiringOptions): Promise<PagedResult<AiringSchedule>>;
1007
+ /** Get currently releasing manga. */
1008
+ getAiredChapters(options?: GetRecentChaptersOptions): Promise<PagedResult<Media>>;
1009
+ /** Get the detailed schedule for the current week, sorted by day. */
1010
+ getWeeklySchedule(date?: Date): Promise<WeeklySchedule>;
1011
+ /** Get upcoming (not yet released) media. */
1012
+ getPlanning(options?: GetPlanningOptions): Promise<PagedResult<Media>>;
1013
+ /** Get recommendations for a specific media. */
1014
+ getRecommendations(mediaId: number, options?: Omit<GetRecommendationsOptions, "mediaId">): Promise<PagedResult<Recommendation>>;
1015
+ /** Get anime (or manga) for a specific season and year. */
1016
+ getMediaBySeason(options: GetSeasonOptions): Promise<PagedResult<Media>>;
1017
+ /** Fetch a character by AniList ID. Pass `{ voiceActors: true }` to include VA data. */
907
1018
  getCharacter(id: number, include?: CharacterIncludeOptions): Promise<Character>;
908
- /**
909
- * Search for characters by name.
910
- *
911
- * @param options - Search / pagination parameters (includes optional `voiceActors`)
912
- * @returns Paginated results with matching characters
913
- *
914
- * @example
915
- * ```ts
916
- * const result = await client.searchCharacters({ query: "Luffy", perPage: 5 });
917
- *
918
- * // With voice actors
919
- * const result = await client.searchCharacters({ query: "Luffy", voiceActors: true });
920
- * ```
921
- */
1019
+ /** Search for characters by name. */
922
1020
  searchCharacters(options?: SearchCharacterOptions): Promise<PagedResult<Character>>;
923
- /**
924
- * Fetch a staff member by AniList ID.
925
- *
926
- * @param id - The AniList staff ID
927
- * @param include - Optional include options to fetch related data (e.g. media)
928
- * @returns The staff object
929
- *
930
- * @example
931
- * ```ts
932
- * const staff = await client.getStaff(95001);
933
- * console.log(staff.name.full);
934
- *
935
- * // With media the staff worked on
936
- * const staff = await client.getStaff(95001, { media: true });
937
- * staff.staffMedia?.nodes.forEach((m) => console.log(m.title.romaji));
938
- * ```
939
- */
1021
+ /** Fetch a staff member by AniList ID. Pass `{ media: true }` or `{ media: { perPage } }` for media credits. */
940
1022
  getStaff(id: number, include?: StaffIncludeOptions): Promise<Staff>;
941
- /**
942
- * Search for staff (voice actors, directors, etc.).
943
- *
944
- * @param options - Search / pagination parameters
945
- * @returns Paginated results with matching staff
946
- *
947
- * @example
948
- * ```ts
949
- * const result = await client.searchStaff({ query: "Miyazaki", perPage: 5 });
950
- * ```
951
- */
1023
+ /** Search for staff (voice actors, directors, etc.). */
952
1024
  searchStaff(options?: SearchStaffOptions): Promise<PagedResult<Staff>>;
953
1025
  /**
954
1026
  * Fetch a user by AniList ID or username.
955
1027
  *
956
1028
  * @param idOrName - The AniList user ID (number) or username (string)
957
- * @returns The user object
958
- *
959
- * @example
960
- * ```ts
961
- * const user = await client.getUser(1);
962
- * const user2 = await client.getUser("AniList");
963
- * console.log(user.name);
964
- * ```
965
1029
  */
966
1030
  getUser(idOrName: number | string): Promise<User>;
967
- /**
968
- * Fetch a user by username.
969
- *
970
- * @deprecated Use `getUser(name)` instead.
971
- * @param name - The AniList username
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
980
- *
981
- * @example
982
- * ```ts
983
- * const result = await client.searchUsers({ query: "AniList", perPage: 5 });
984
- * ```
985
- */
1031
+ /** Search for users by name. */
986
1032
  searchUsers(options?: SearchUserOptions): Promise<PagedResult<User>>;
987
- /**
988
- * Execute an arbitrary GraphQL query against the AniList API.
989
- * Useful for advanced use-cases not covered by the built-in methods.
990
- *
991
- * @param query - A valid GraphQL query string
992
- * @param variables - Optional variables object
993
- */
994
- raw<T = unknown>(query: string, variables?: Record<string, unknown>): Promise<T>;
995
- /**
996
- * Get recently aired anime episodes.
997
- *
998
- * By default returns episodes that aired in the last 24 hours.
999
- *
1000
- * @param options - Filter / pagination parameters
1001
- * @returns Paginated list of airing schedule entries
1002
- *
1003
- * @example
1004
- * ```ts
1005
- * // Episodes that aired in the last 48h
1006
- * const recent = await client.getAiredEpisodes({
1007
- * airingAtGreater: Math.floor(Date.now() / 1000) - 48 * 3600,
1008
- * });
1009
- * ```
1010
- */
1011
- getAiredEpisodes(options?: GetAiringOptions): Promise<PagedResult<AiringSchedule>>;
1012
- /**
1013
- * Get manga that are currently releasing, sorted by most recently updated.
1014
- *
1015
- * This is the closest equivalent to "recently released chapters" on AniList,
1016
- * since the API does not expose per-chapter airing schedules for manga.
1017
- *
1018
- * @param options - Pagination parameters
1019
- * @returns Paginated list of currently releasing manga
1020
- *
1021
- * @example
1022
- * ```ts
1023
- * const chapters = await client.getAiredChapters({ perPage: 10 });
1024
- * ```
1025
- */
1026
- getAiredChapters(options?: GetRecentChaptersOptions): Promise<PagedResult<Media>>;
1027
- /**
1028
- * Get upcoming (not yet released) anime and/or manga, sorted by popularity.
1029
- *
1030
- * @param options - Filter / pagination parameters
1031
- * @returns Paginated list of planned media
1032
- *
1033
- * @example
1034
- * ```ts
1035
- * import { MediaType } from "ani-client";
1036
- *
1037
- * // Most anticipated upcoming anime
1038
- * const planning = await client.getPlanning({ type: MediaType.ANIME, perPage: 10 });
1039
- * ```
1040
- */
1041
- getPlanning(options?: GetPlanningOptions): Promise<PagedResult<Media>>;
1042
- /**
1043
- * Get recommendations for a specific media.
1044
- *
1045
- * Returns other anime/manga that users have recommended based on the given media.
1046
- *
1047
- * @param mediaId - The AniList media ID
1048
- * @param options - Optional sort / pagination parameters
1049
- * @returns Paginated list of recommendations
1050
- *
1051
- * @example
1052
- * ```ts
1053
- * // Get recommendations for Cowboy Bebop
1054
- * const recs = await client.getRecommendations(1);
1055
- * recs.results.forEach((r) =>
1056
- * console.log(`${r.mediaRecommendation.title.romaji} (rating: ${r.rating})`)
1057
- * );
1058
- * ```
1059
- */
1060
- getRecommendations(mediaId: number, options?: Omit<GetRecommendationsOptions, "mediaId">): Promise<PagedResult<Recommendation>>;
1061
- /**
1062
- * Get anime (or manga) for a specific season and year.
1063
- *
1064
- * @param options - Season, year and optional filter / pagination parameters
1065
- * @returns Paginated list of media for the given season
1066
- *
1067
- * @example
1068
- * ```ts
1069
- * import { MediaSeason } from "ani-client";
1070
- *
1071
- * const winter2026 = await client.getMediaBySeason({
1072
- * season: MediaSeason.WINTER,
1073
- * seasonYear: 2026,
1074
- * perPage: 10,
1075
- * });
1076
- * ```
1077
- */
1078
- getMediaBySeason(options: GetSeasonOptions): Promise<PagedResult<Media>>;
1079
- /**
1080
- * Get a user's anime or manga list.
1081
- *
1082
- * Provide either `userId` or `userName` to identify the user.
1083
- * Requires `type` (ANIME or MANGA). Optionally filter by list status.
1084
- *
1085
- * @param options - User identifier, media type, and optional filters
1086
- * @returns Paginated list of media list entries
1087
- *
1088
- * @example
1089
- * ```ts
1090
- * import { MediaType, MediaListStatus } from "ani-client";
1091
- *
1092
- * // Get a user's completed anime list
1093
- * const list = await client.getUserMediaList({
1094
- * userName: "AniList",
1095
- * type: MediaType.ANIME,
1096
- * status: MediaListStatus.COMPLETED,
1097
- * });
1098
- * list.results.forEach((entry) =>
1099
- * console.log(`${entry.media.title.romaji} — ${entry.score}/100`)
1100
- * );
1101
- * ```
1102
- */
1033
+ /** Get a user's anime or manga list. */
1103
1034
  getUserMediaList(options: GetUserMediaListOptions): Promise<PagedResult<MediaListEntry>>;
1104
1035
  /**
1105
- * Fetch a studio by its AniList ID.
1106
- *
1107
- * Returns studio details along with its most popular productions.
1108
- *
1109
- * @param id - The AniList studio ID
1110
- */
1111
- getStudio(id: number): Promise<Studio>;
1112
- /**
1113
- * Search for studios by name.
1036
+ * Fetch a user's favorite anime, manga, characters, staff, and studios.
1114
1037
  *
1115
- * @param options - Search / pagination parameters
1116
- * @returns Paginated list of studios
1038
+ * @param idOrName - AniList user ID (number) or username (string)
1039
+ * @returns The user's favorites grouped by category
1117
1040
  *
1118
1041
  * @example
1119
- * ```ts
1120
- * const studios = await client.searchStudios({ query: "MAPPA" });
1042
+ * ```typescript
1043
+ * const favs = await client.getUserFavorites("AniList");
1044
+ * favs.anime.forEach(a => console.log(a.title.romaji));
1121
1045
  * ```
1122
1046
  */
1047
+ getUserFavorites(idOrName: number | string): Promise<UserFavorites>;
1048
+ /** Fetch a studio by its AniList ID. */
1049
+ getStudio(id: number): Promise<Studio>;
1050
+ /** Search for studios by name. */
1123
1051
  searchStudios(options?: SearchStudioOptions): Promise<PagedResult<Studio>>;
1124
- /**
1125
- * Get all available genres on AniList.
1126
- *
1127
- * @returns Array of genre strings (e.g. "Action", "Adventure", ...)
1128
- */
1052
+ /** Fetch a forum thread by its AniList ID. */
1053
+ getThread(id: number): Promise<Thread>;
1054
+ /** Get recent forum threads, optionally filtered by search, media, or category. */
1055
+ getRecentThreads(options?: SearchThreadOptions): Promise<PagedResult<Thread>>;
1056
+ /** Get all available genres on AniList. */
1129
1057
  getGenres(): Promise<string[]>;
1130
- /**
1131
- * Get all available media tags on AniList.
1132
- *
1133
- * @returns Array of tag objects with id, name, description, category, isAdult
1134
- */
1058
+ /** Get all available media tags on AniList. */
1135
1059
  getTags(): Promise<MediaTag[]>;
1060
+ /** Execute an arbitrary GraphQL query against the AniList API. */
1061
+ raw<T>(query: string, variables?: Record<string, unknown>): Promise<T>;
1136
1062
  /**
1137
- * Auto-paginating async iterator.
1138
- *
1139
- * Wraps any paginated method and yields individual items across all pages.
1140
- * Stops when `hasNextPage` is `false` or `maxPages` is reached.
1063
+ * Auto-paginating async iterator. Yields individual items across all pages.
1141
1064
  *
1142
1065
  * @param fetchPage - A function that takes a page number and returns a `PagedResult<T>`
1143
1066
  * @param maxPages - Maximum number of pages to fetch (default: Infinity)
1144
- * @returns An async iterable iterator of individual items
1145
- *
1146
- * @example
1147
- * ```ts
1148
- * // Iterate over all search results
1149
- * for await (const anime of client.paginate((page) =>
1150
- * client.searchMedia({ query: "Naruto", page, perPage: 10 })
1151
- * )) {
1152
- * console.log(anime.title.romaji);
1153
- * }
1154
- *
1155
- * // Limit to 3 pages
1156
- * for await (const anime of client.paginate(
1157
- * (page) => client.getTrending(MediaType.ANIME, page, 20),
1158
- * 3,
1159
- * )) {
1160
- * console.log(anime.title.romaji);
1161
- * }
1162
- * ```
1163
1067
  */
1164
1068
  paginate<T>(fetchPage: (page: number) => Promise<PagedResult<T>>, maxPages?: number): AsyncGenerator<T, void, undefined>;
1165
- /**
1166
- * Fetch multiple media entries in a single API request.
1167
- * Uses GraphQL aliases to batch up to 50 IDs per call.
1168
- *
1169
- * @param ids - Array of AniList media IDs
1170
- * @returns Array of media objects (same order as input IDs)
1171
- */
1069
+ /** Fetch multiple media entries in a single API request. */
1172
1070
  getMediaBatch(ids: number[]): Promise<Media[]>;
1173
- /**
1174
- * Fetch multiple characters in a single API request.
1175
- *
1176
- * @param ids - Array of AniList character IDs
1177
- * @returns Array of character objects (same order as input IDs)
1178
- */
1071
+ /** Fetch multiple characters in a single API request. */
1179
1072
  getCharacterBatch(ids: number[]): Promise<Character[]>;
1180
- /**
1181
- * Fetch multiple staff members in a single API request.
1182
- *
1183
- * @param ids - Array of AniList staff IDs
1184
- * @returns Array of staff objects (same order as input IDs)
1185
- */
1073
+ /** Fetch multiple staff members in a single API request. */
1186
1074
  getStaffBatch(ids: number[]): Promise<Staff[]>;
1187
1075
  /** @internal */
1188
1076
  private executeBatch;
1189
- /**
1190
- * Clear the entire response cache.
1191
- */
1077
+ /** Clear the entire response cache. */
1192
1078
  clearCache(): Promise<void>;
1193
- /**
1194
- * Number of entries currently in the cache.
1195
- * For async adapters like Redis, this may return a Promise.
1196
- */
1079
+ /** Number of entries currently in the cache. */
1197
1080
  get cacheSize(): number | Promise<number>;
1198
- /**
1199
- * Remove cache entries whose key matches the given pattern.
1200
- *
1201
- * @param pattern — A string (converted to RegExp) or RegExp
1202
- * @returns Number of entries removed
1203
- */
1081
+ /** Remove cache entries whose key matches the given pattern. */
1204
1082
  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
- */
1083
+ /** Clean up resources held by the client. */
1212
1084
  destroy(): Promise<void>;
1213
1085
  }
1214
1086
 
@@ -1342,6 +1214,7 @@ declare class RateLimiter {
1342
1214
  private readonly enabled;
1343
1215
  private readonly timeoutMs;
1344
1216
  private readonly retryOnNetworkError;
1217
+ private readonly retryStrategy?;
1345
1218
  /** @internal — sliding window: circular buffer of timestamps */
1346
1219
  private readonly timestamps;
1347
1220
  private head;
@@ -1359,11 +1232,20 @@ declare class RateLimiter {
1359
1232
  onRetry?: (attempt: number, reason: string, delayMs: number) => void;
1360
1233
  onRateLimit?: (retryAfterMs: number) => void;
1361
1234
  }): Promise<Response>;
1362
- /** @internal — Exponential backoff with jitter, capped at 30s */
1235
+ /** @internal — Exponential backoff with jitter, capped at 30s (or custom strategy) */
1363
1236
  private exponentialDelay;
1364
1237
  /** @internal */
1365
1238
  private fetchWithTimeout;
1366
1239
  private sleep;
1367
1240
  }
1368
1241
 
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 };
1242
+ /**
1243
+ * Parses AniList specific markdown into standard HTML.
1244
+ * Includes formatting for spoilers, images, videos (youtube/webm), and standard markdown elements.
1245
+ *
1246
+ * @param text The AniList markdown text to parse
1247
+ * @returns The parsed HTML string
1248
+ */
1249
+ declare function parseAniListMarkdown(text: string): string;
1250
+
1251
+ 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 DayOfWeek, type ExternalLink, type FavoriteCharacterNode, type FavoriteMediaNode, type FavoriteStaffNode, type FavoriteStudioNode, 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 RateLimitInfo, type RateLimitOptions, RateLimiter, type Recommendation, RecommendationSort, RedisCache, type RedisCacheOptions, type RedisLikeClient, type ResponseMeta, type ScoreDistribution, type SearchCharacterOptions, type SearchMediaOptions, type SearchStaffOptions, type SearchStudioOptions, type SearchThreadOptions, type SearchUserOptions, type Staff, type StaffImage, type StaffIncludeOptions, type StaffMediaNode, type StaffName, StaffSort, type StatusDistribution, type StreamingEpisode, type Studio, type StudioConnection, type Thread, type ThreadCategory, type ThreadMediaCategory, ThreadSort, type User, type UserAvatar, type UserFavorites, UserSort, type UserStatistics, type VoiceActor, type WeeklySchedule, parseAniListMarkdown };