ani-client 1.4.3 → 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/dist/index.d.ts CHANGED
@@ -96,6 +96,18 @@ interface AniListClientOptions {
96
96
  hooks?: AniListHooks;
97
97
  }
98
98
 
99
+ declare enum StaffSort {
100
+ ID = "ID",
101
+ ID_DESC = "ID_DESC",
102
+ ROLE = "ROLE",
103
+ ROLE_DESC = "ROLE_DESC",
104
+ LANGUAGE = "LANGUAGE",
105
+ LANGUAGE_DESC = "LANGUAGE_DESC",
106
+ SEARCH_MATCH = "SEARCH_MATCH",
107
+ FAVOURITES = "FAVOURITES",
108
+ FAVOURITES_DESC = "FAVOURITES_DESC",
109
+ RELEVANCE = "RELEVANCE"
110
+ }
99
111
  interface StaffName {
100
112
  first: string | null;
101
113
  middle: string | null;
@@ -176,7 +188,7 @@ interface StaffIncludeOptions {
176
188
  }
177
189
  interface SearchStaffOptions {
178
190
  query?: string;
179
- sort?: CharacterSort[];
191
+ sort?: StaffSort[];
180
192
  page?: number;
181
193
  perPage?: number;
182
194
  }
@@ -259,32 +271,113 @@ interface SearchCharacterOptions {
259
271
  voiceActors?: boolean;
260
272
  }
261
273
 
262
- interface Studio {
274
+ declare enum MediaListStatus {
275
+ CURRENT = "CURRENT",
276
+ PLANNING = "PLANNING",
277
+ COMPLETED = "COMPLETED",
278
+ DROPPED = "DROPPED",
279
+ PAUSED = "PAUSED",
280
+ REPEATING = "REPEATING"
281
+ }
282
+ declare enum MediaListSort {
283
+ MEDIA_ID = "MEDIA_ID",
284
+ MEDIA_ID_DESC = "MEDIA_ID_DESC",
285
+ SCORE = "SCORE",
286
+ SCORE_DESC = "SCORE_DESC",
287
+ STATUS = "STATUS",
288
+ STATUS_DESC = "STATUS_DESC",
289
+ PROGRESS = "PROGRESS",
290
+ PROGRESS_DESC = "PROGRESS_DESC",
291
+ PROGRESS_VOLUMES = "PROGRESS_VOLUMES",
292
+ PROGRESS_VOLUMES_DESC = "PROGRESS_VOLUMES_DESC",
293
+ REPEAT = "REPEAT",
294
+ REPEAT_DESC = "REPEAT_DESC",
295
+ PRIORITY = "PRIORITY",
296
+ PRIORITY_DESC = "PRIORITY_DESC",
297
+ STARTED_ON = "STARTED_ON",
298
+ STARTED_ON_DESC = "STARTED_ON_DESC",
299
+ FINISHED_ON = "FINISHED_ON",
300
+ FINISHED_ON_DESC = "FINISHED_ON_DESC",
301
+ ADDED_TIME = "ADDED_TIME",
302
+ ADDED_TIME_DESC = "ADDED_TIME_DESC",
303
+ UPDATED_TIME = "UPDATED_TIME",
304
+ UPDATED_TIME_DESC = "UPDATED_TIME_DESC",
305
+ MEDIA_TITLE_ROMAJI = "MEDIA_TITLE_ROMAJI",
306
+ MEDIA_TITLE_ROMAJI_DESC = "MEDIA_TITLE_ROMAJI_DESC",
307
+ MEDIA_TITLE_ENGLISH = "MEDIA_TITLE_ENGLISH",
308
+ MEDIA_TITLE_ENGLISH_DESC = "MEDIA_TITLE_ENGLISH_DESC",
309
+ MEDIA_TITLE_NATIVE = "MEDIA_TITLE_NATIVE",
310
+ MEDIA_TITLE_NATIVE_DESC = "MEDIA_TITLE_NATIVE_DESC",
311
+ MEDIA_POPULARITY = "MEDIA_POPULARITY",
312
+ MEDIA_POPULARITY_DESC = "MEDIA_POPULARITY_DESC"
313
+ }
314
+ interface MediaListEntry {
263
315
  id: number;
264
- name: string;
265
- isAnimationStudio: boolean;
266
- siteUrl: string | null;
316
+ mediaId: number;
317
+ status: MediaListStatus;
318
+ score: number | null;
319
+ progress: number | null;
320
+ progressVolumes: number | null;
321
+ repeat: number | null;
322
+ priority: number | null;
323
+ private: boolean | null;
324
+ notes: string | null;
325
+ startedAt: FuzzyDate | null;
326
+ completedAt: FuzzyDate | null;
327
+ updatedAt: number | null;
328
+ createdAt: number | null;
329
+ media: Media;
267
330
  }
268
- interface StudioConnection {
269
- nodes: Studio[];
331
+ interface GetUserMediaListOptions {
332
+ /** User ID (provide either userId or userName) */
333
+ userId?: number;
334
+ /** Username (provide either userId or userName) */
335
+ userName?: string;
336
+ /** ANIME or MANGA */
337
+ type: MediaType;
338
+ /** Filter by list status (CURRENT, COMPLETED, etc.) */
339
+ status?: MediaListStatus;
340
+ /** Sort order */
341
+ sort?: MediaListSort[];
342
+ page?: number;
343
+ perPage?: number;
270
344
  }
271
- interface StudioDetail {
345
+
346
+ interface Studio {
272
347
  id: number;
273
348
  name: string;
274
349
  isAnimationStudio: boolean;
275
350
  siteUrl: string | null;
276
- favourites: number | null;
277
- media: {
351
+ favourites?: number | null;
352
+ media?: {
278
353
  pageInfo: PageInfo;
279
354
  nodes: Pick<Media, "id" | "title" | "type" | "format" | "coverImage" | "siteUrl">[];
280
355
  } | null;
281
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;
282
364
  interface SearchStudioOptions {
283
365
  query?: string;
284
366
  page?: number;
285
367
  perPage?: number;
286
368
  }
287
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
+ }
288
381
  interface UserAvatar {
289
382
  large: string | null;
290
383
  medium: string | null;
@@ -314,11 +407,34 @@ interface User {
314
407
  manga: UserStatistics;
315
408
  } | null;
316
409
  }
410
+ interface SearchUserOptions {
411
+ query?: string;
412
+ sort?: UserSort[];
413
+ page?: number;
414
+ perPage?: number;
415
+ }
317
416
 
318
417
  declare enum MediaType {
319
418
  ANIME = "ANIME",
320
419
  MANGA = "MANGA"
321
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
+ }
322
438
  declare enum MediaFormat {
323
439
  TV = "TV",
324
440
  TV_SHORT = "TV_SHORT",
@@ -462,7 +578,7 @@ interface ScoreDistribution {
462
578
  amount: number;
463
579
  }
464
580
  interface StatusDistribution {
465
- status: string;
581
+ status: MediaListStatus | string;
466
582
  amount: number;
467
583
  }
468
584
  interface MediaStats {
@@ -474,6 +590,13 @@ interface MediaRecommendationNode {
474
590
  rating: number | null;
475
591
  mediaRecommendation: Pick<Media, "id" | "title" | "type" | "format" | "coverImage" | "averageScore" | "siteUrl">;
476
592
  }
593
+ interface NextAiringEpisode {
594
+ id: number;
595
+ airingAt: number;
596
+ episode: number;
597
+ mediaId: number;
598
+ timeUntilAiring: number;
599
+ }
477
600
  interface Media {
478
601
  id: number;
479
602
  idMal: number | null;
@@ -492,7 +615,7 @@ interface Media {
492
615
  volumes: number | null;
493
616
  countryOfOrigin: string | null;
494
617
  isLicensed: boolean | null;
495
- source: string | null;
618
+ source: MediaSource | null;
496
619
  hashtag: string | null;
497
620
  trailer: MediaTrailer | null;
498
621
  coverImage: MediaCoverImage;
@@ -515,6 +638,7 @@ interface Media {
515
638
  recommendations?: {
516
639
  nodes: MediaRecommendationNode[];
517
640
  };
641
+ nextAiringEpisode: NextAiringEpisode | null;
518
642
  isAdult: boolean | null;
519
643
  siteUrl: string | null;
520
644
  }
@@ -525,8 +649,18 @@ interface SearchMediaOptions {
525
649
  status?: MediaStatus;
526
650
  season?: MediaSeason;
527
651
  seasonYear?: number;
652
+ /** Single genre filter (kept for backward compat) */
528
653
  genre?: string;
654
+ /** Single tag filter (kept for backward compat) */
529
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[];
530
664
  isAdult?: boolean;
531
665
  sort?: MediaSort[];
532
666
  page?: number;
@@ -633,78 +767,6 @@ interface AiringSchedule {
633
767
  media: Media;
634
768
  }
635
769
 
636
- declare enum MediaListStatus {
637
- CURRENT = "CURRENT",
638
- PLANNING = "PLANNING",
639
- COMPLETED = "COMPLETED",
640
- DROPPED = "DROPPED",
641
- PAUSED = "PAUSED",
642
- REPEATING = "REPEATING"
643
- }
644
- declare enum MediaListSort {
645
- MEDIA_ID = "MEDIA_ID",
646
- MEDIA_ID_DESC = "MEDIA_ID_DESC",
647
- SCORE = "SCORE",
648
- SCORE_DESC = "SCORE_DESC",
649
- STATUS = "STATUS",
650
- STATUS_DESC = "STATUS_DESC",
651
- PROGRESS = "PROGRESS",
652
- PROGRESS_DESC = "PROGRESS_DESC",
653
- PROGRESS_VOLUMES = "PROGRESS_VOLUMES",
654
- PROGRESS_VOLUMES_DESC = "PROGRESS_VOLUMES_DESC",
655
- REPEAT = "REPEAT",
656
- REPEAT_DESC = "REPEAT_DESC",
657
- PRIORITY = "PRIORITY",
658
- PRIORITY_DESC = "PRIORITY_DESC",
659
- STARTED_ON = "STARTED_ON",
660
- STARTED_ON_DESC = "STARTED_ON_DESC",
661
- FINISHED_ON = "FINISHED_ON",
662
- FINISHED_ON_DESC = "FINISHED_ON_DESC",
663
- ADDED_TIME = "ADDED_TIME",
664
- ADDED_TIME_DESC = "ADDED_TIME_DESC",
665
- UPDATED_TIME = "UPDATED_TIME",
666
- UPDATED_TIME_DESC = "UPDATED_TIME_DESC",
667
- MEDIA_TITLE_ROMAJI = "MEDIA_TITLE_ROMAJI",
668
- MEDIA_TITLE_ROMAJI_DESC = "MEDIA_TITLE_ROMAJI_DESC",
669
- MEDIA_TITLE_ENGLISH = "MEDIA_TITLE_ENGLISH",
670
- MEDIA_TITLE_ENGLISH_DESC = "MEDIA_TITLE_ENGLISH_DESC",
671
- MEDIA_TITLE_NATIVE = "MEDIA_TITLE_NATIVE",
672
- MEDIA_TITLE_NATIVE_DESC = "MEDIA_TITLE_NATIVE_DESC",
673
- MEDIA_POPULARITY = "MEDIA_POPULARITY",
674
- MEDIA_POPULARITY_DESC = "MEDIA_POPULARITY_DESC"
675
- }
676
- interface MediaListEntry {
677
- id: number;
678
- mediaId: number;
679
- status: MediaListStatus;
680
- score: number | null;
681
- progress: number | null;
682
- progressVolumes: number | null;
683
- repeat: number | null;
684
- priority: number | null;
685
- private: boolean | null;
686
- notes: string | null;
687
- startedAt: FuzzyDate | null;
688
- completedAt: FuzzyDate | null;
689
- updatedAt: number | null;
690
- createdAt: number | null;
691
- media: Media;
692
- }
693
- interface GetUserMediaListOptions {
694
- /** User ID (provide either userId or userName) */
695
- userId?: number;
696
- /** Username (provide either userId or userName) */
697
- userName?: string;
698
- /** ANIME or MANGA */
699
- type: MediaType;
700
- /** Filter by list status (CURRENT, COMPLETED, etc.) */
701
- status?: MediaListStatus;
702
- /** Sort order */
703
- sort?: MediaListSort[];
704
- page?: number;
705
- perPage?: number;
706
- }
707
-
708
770
  /**
709
771
  * Lightweight AniList GraphQL client with built-in caching and rate limiting.
710
772
  *
@@ -802,6 +864,26 @@ declare class AniListClient {
802
864
  * @param perPage - Results per page (default 20, max 50)
803
865
  */
804
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>>;
805
887
  /**
806
888
  * Fetch a character by AniList ID.
807
889
  *
@@ -869,31 +951,39 @@ declare class AniListClient {
869
951
  */
870
952
  searchStaff(options?: SearchStaffOptions): Promise<PagedResult<Staff>>;
871
953
  /**
872
- * Fetch a user by AniList ID.
954
+ * Fetch a user by AniList ID or username.
873
955
  *
874
- * @param id - The AniList user ID
956
+ * @param idOrName - The AniList user ID (number) or username (string)
875
957
  * @returns The user object
876
958
  *
877
959
  * @example
878
960
  * ```ts
879
961
  * const user = await client.getUser(1);
962
+ * const user2 = await client.getUser("AniList");
880
963
  * console.log(user.name);
881
964
  * ```
882
965
  */
883
- getUser(id: number): Promise<User>;
966
+ getUser(idOrName: number | string): Promise<User>;
884
967
  /**
885
968
  * Fetch a user by username.
886
969
  *
970
+ * @deprecated Use `getUser(name)` instead.
887
971
  * @param name - The AniList username
888
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
889
980
  *
890
981
  * @example
891
982
  * ```ts
892
- * const user = await client.getUserByName("AniList");
893
- * console.log(user.statistics);
983
+ * const result = await client.searchUsers({ query: "AniList", perPage: 5 });
894
984
  * ```
895
985
  */
896
- getUserByName(name: string): Promise<User>;
986
+ searchUsers(options?: SearchUserOptions): Promise<PagedResult<User>>;
897
987
  /**
898
988
  * Execute an arbitrary GraphQL query against the AniList API.
899
989
  * Useful for advanced use-cases not covered by the built-in methods.
@@ -1018,7 +1108,7 @@ declare class AniListClient {
1018
1108
  *
1019
1109
  * @param id - The AniList studio ID
1020
1110
  */
1021
- getStudio(id: number): Promise<StudioDetail>;
1111
+ getStudio(id: number): Promise<Studio>;
1022
1112
  /**
1023
1113
  * Search for studios by name.
1024
1114
  *
@@ -1030,7 +1120,7 @@ declare class AniListClient {
1030
1120
  * const studios = await client.searchStudios({ query: "MAPPA" });
1031
1121
  * ```
1032
1122
  */
1033
- searchStudios(options?: SearchStudioOptions): Promise<PagedResult<StudioDetail>>;
1123
+ searchStudios(options?: SearchStudioOptions): Promise<PagedResult<Studio>>;
1034
1124
  /**
1035
1125
  * Get all available genres on AniList.
1036
1126
  *
@@ -1112,6 +1202,14 @@ declare class AniListClient {
1112
1202
  * @returns Number of entries removed
1113
1203
  */
1114
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>;
1115
1213
  }
1116
1214
 
1117
1215
  /**
@@ -1148,7 +1246,10 @@ declare class MemoryCache implements CacheAdapter {
1148
1246
  /**
1149
1247
  * Remove all entries whose key matches the given pattern.
1150
1248
  *
1151
- * @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.
1152
1253
  * @returns Number of entries removed.
1153
1254
  */
1154
1255
  invalidate(pattern: string | RegExp): number;
@@ -1241,8 +1342,10 @@ declare class RateLimiter {
1241
1342
  private readonly enabled;
1242
1343
  private readonly timeoutMs;
1243
1344
  private readonly retryOnNetworkError;
1244
- /** @internal */
1245
- private timestamps;
1345
+ /** @internal — sliding window: circular buffer of timestamps */
1346
+ private readonly timestamps;
1347
+ private head;
1348
+ private count;
1246
1349
  constructor(options?: RateLimitOptions);
1247
1350
  /**
1248
1351
  * Wait until it's safe to make a request (respects rate limit window).
@@ -1250,14 +1353,17 @@ declare class RateLimiter {
1250
1353
  acquire(): Promise<void>;
1251
1354
  /**
1252
1355
  * Execute a fetch with automatic retry on 429 responses and network errors.
1356
+ * Uses exponential backoff with jitter for retry delays.
1253
1357
  */
1254
1358
  fetchWithRetry(url: string, init: RequestInit, hooks?: {
1255
1359
  onRetry?: (attempt: number, reason: string, delayMs: number) => void;
1256
1360
  onRateLimit?: (retryAfterMs: number) => void;
1257
1361
  }): Promise<Response>;
1362
+ /** @internal — Exponential backoff with jitter, capped at 30s */
1363
+ private exponentialDelay;
1258
1364
  /** @internal */
1259
1365
  private fetchWithTimeout;
1260
1366
  private sleep;
1261
1367
  }
1262
1368
 
1263
- 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, 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 };