ani-client 1.6.1 → 1.7.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
@@ -225,21 +225,11 @@ interface SearchStaffOptions {
225
225
  perPage?: number;
226
226
  }
227
227
  /** Compact voice actor data returned inside character edges. */
228
- interface VoiceActor {
229
- id: number;
230
- name: {
231
- first: string | null;
232
- middle: string | null;
233
- last: string | null;
234
- full: string | null;
235
- native: string | null;
228
+ interface VoiceActor extends Pick<Staff, "id" | "image" | "gender" | "primaryOccupations" | "siteUrl"> {
229
+ name: StaffName & {
236
230
  userPreferred: string | null;
237
231
  };
238
232
  languageV2: string | null;
239
- image: StaffImage;
240
- gender: string | null;
241
- primaryOccupations: string[];
242
- siteUrl: string | null;
243
233
  }
244
234
 
245
235
  declare enum CharacterSort {
@@ -389,8 +379,18 @@ interface Studio {
389
379
  interface StudioConnection {
390
380
  nodes: Studio[];
391
381
  }
382
+ declare enum StudioSort {
383
+ ID = "ID",
384
+ ID_DESC = "ID_DESC",
385
+ NAME = "NAME",
386
+ NAME_DESC = "NAME_DESC",
387
+ SEARCH_MATCH = "SEARCH_MATCH",
388
+ FAVOURITES = "FAVOURITES",
389
+ FAVOURITES_DESC = "FAVOURITES_DESC"
390
+ }
392
391
  interface SearchStudioOptions {
393
392
  query?: string;
393
+ sort?: StudioSort[];
394
394
  page?: number;
395
395
  perPage?: number;
396
396
  }
@@ -443,18 +443,10 @@ interface SearchUserOptions {
443
443
  }
444
444
  interface FavoriteMediaNode {
445
445
  id: number;
446
- title: {
447
- romaji: string | null;
448
- english: string | null;
449
- native: string | null;
450
- userPreferred: string | null;
451
- };
452
- coverImage: {
453
- large: string | null;
454
- medium: string | null;
455
- };
456
- type: string | null;
457
- format: string | null;
446
+ title: MediaTitle;
447
+ coverImage: Pick<MediaCoverImage, "large" | "medium">;
448
+ type: MediaType | null;
449
+ format: MediaFormat | null;
458
450
  siteUrl: string | null;
459
451
  }
460
452
  interface FavoriteCharacterNode {
@@ -658,7 +650,7 @@ interface ScoreDistribution {
658
650
  amount: number;
659
651
  }
660
652
  interface StatusDistribution {
661
- status: MediaListStatus | string;
653
+ status: MediaListStatus;
662
654
  amount: number;
663
655
  }
664
656
  interface MediaStats {
@@ -889,17 +881,9 @@ interface ThreadCategory {
889
881
  }
890
882
  interface ThreadMediaCategory {
891
883
  id: number;
892
- title: {
893
- romaji: string | null;
894
- english: string | null;
895
- native: string | null;
896
- userPreferred: string | null;
897
- };
898
- type: string;
899
- coverImage: {
900
- large: string | null;
901
- medium: string | null;
902
- } | null;
884
+ title: MediaTitle;
885
+ type: MediaType;
886
+ coverImage: Pick<MediaCoverImage, "large" | "medium"> | null;
903
887
  siteUrl: string | null;
904
888
  }
905
889
  /** Sort options for thread queries. */
@@ -1006,7 +990,15 @@ declare class AniListClient {
1006
990
  getTopRated(type?: MediaType, page?: number, perPage?: number): Promise<PagedResult<Media>>;
1007
991
  /** Get recently aired anime episodes. */
1008
992
  getAiredEpisodes(options?: GetAiringOptions): Promise<PagedResult<AiringSchedule>>;
1009
- /** Get currently releasing manga. */
993
+ /**
994
+ * Get currently releasing manga sorted by most recently updated.
995
+ *
996
+ * @param options - Pagination parameters
997
+ */
998
+ getRecentlyUpdatedManga(options?: GetRecentChaptersOptions): Promise<PagedResult<Media>>;
999
+ /**
1000
+ * @deprecated Use `getRecentlyUpdatedManga` instead. This alias will be removed in v2.
1001
+ */
1010
1002
  getAiredChapters(options?: GetRecentChaptersOptions): Promise<PagedResult<Media>>;
1011
1003
  /** Get the detailed schedule for the current week, sorted by day. */
1012
1004
  getWeeklySchedule(date?: Date): Promise<WeeklySchedule>;
@@ -1245,19 +1237,6 @@ declare class RateLimiter {
1245
1237
  dispose(): void;
1246
1238
  }
1247
1239
 
1248
- /**
1249
- * Parses AniList specific markdown into standard HTML.
1250
- * Includes formatting for spoilers, images, videos (youtube/webm), headings,
1251
- * lists, code blocks, and standard markdown elements.
1252
- *
1253
- * @security This function escapes HTML entities to prevent XSS attacks.
1254
- * However, the output is still raw HTML — consumers should always use a
1255
- * Content Security Policy and consider additional sanitization when rendering
1256
- * user-generated content in a browser.
1257
- *
1258
- * @param text The AniList markdown text to parse
1259
- * @returns The parsed HTML string
1260
- */
1261
1240
  declare function parseAniListMarkdown(text: string): string;
1262
1241
 
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 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 };
1242
+ 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, StudioSort, type Thread, type ThreadCategory, type ThreadMediaCategory, ThreadSort, type User, type UserAvatar, type UserFavorites, UserSort, type UserStatistics, type VoiceActor, type WeeklySchedule, parseAniListMarkdown };
package/dist/index.d.ts CHANGED
@@ -225,21 +225,11 @@ interface SearchStaffOptions {
225
225
  perPage?: number;
226
226
  }
227
227
  /** Compact voice actor data returned inside character edges. */
228
- interface VoiceActor {
229
- id: number;
230
- name: {
231
- first: string | null;
232
- middle: string | null;
233
- last: string | null;
234
- full: string | null;
235
- native: string | null;
228
+ interface VoiceActor extends Pick<Staff, "id" | "image" | "gender" | "primaryOccupations" | "siteUrl"> {
229
+ name: StaffName & {
236
230
  userPreferred: string | null;
237
231
  };
238
232
  languageV2: string | null;
239
- image: StaffImage;
240
- gender: string | null;
241
- primaryOccupations: string[];
242
- siteUrl: string | null;
243
233
  }
244
234
 
245
235
  declare enum CharacterSort {
@@ -389,8 +379,18 @@ interface Studio {
389
379
  interface StudioConnection {
390
380
  nodes: Studio[];
391
381
  }
382
+ declare enum StudioSort {
383
+ ID = "ID",
384
+ ID_DESC = "ID_DESC",
385
+ NAME = "NAME",
386
+ NAME_DESC = "NAME_DESC",
387
+ SEARCH_MATCH = "SEARCH_MATCH",
388
+ FAVOURITES = "FAVOURITES",
389
+ FAVOURITES_DESC = "FAVOURITES_DESC"
390
+ }
392
391
  interface SearchStudioOptions {
393
392
  query?: string;
393
+ sort?: StudioSort[];
394
394
  page?: number;
395
395
  perPage?: number;
396
396
  }
@@ -443,18 +443,10 @@ interface SearchUserOptions {
443
443
  }
444
444
  interface FavoriteMediaNode {
445
445
  id: number;
446
- title: {
447
- romaji: string | null;
448
- english: string | null;
449
- native: string | null;
450
- userPreferred: string | null;
451
- };
452
- coverImage: {
453
- large: string | null;
454
- medium: string | null;
455
- };
456
- type: string | null;
457
- format: string | null;
446
+ title: MediaTitle;
447
+ coverImage: Pick<MediaCoverImage, "large" | "medium">;
448
+ type: MediaType | null;
449
+ format: MediaFormat | null;
458
450
  siteUrl: string | null;
459
451
  }
460
452
  interface FavoriteCharacterNode {
@@ -658,7 +650,7 @@ interface ScoreDistribution {
658
650
  amount: number;
659
651
  }
660
652
  interface StatusDistribution {
661
- status: MediaListStatus | string;
653
+ status: MediaListStatus;
662
654
  amount: number;
663
655
  }
664
656
  interface MediaStats {
@@ -889,17 +881,9 @@ interface ThreadCategory {
889
881
  }
890
882
  interface ThreadMediaCategory {
891
883
  id: number;
892
- title: {
893
- romaji: string | null;
894
- english: string | null;
895
- native: string | null;
896
- userPreferred: string | null;
897
- };
898
- type: string;
899
- coverImage: {
900
- large: string | null;
901
- medium: string | null;
902
- } | null;
884
+ title: MediaTitle;
885
+ type: MediaType;
886
+ coverImage: Pick<MediaCoverImage, "large" | "medium"> | null;
903
887
  siteUrl: string | null;
904
888
  }
905
889
  /** Sort options for thread queries. */
@@ -1006,7 +990,15 @@ declare class AniListClient {
1006
990
  getTopRated(type?: MediaType, page?: number, perPage?: number): Promise<PagedResult<Media>>;
1007
991
  /** Get recently aired anime episodes. */
1008
992
  getAiredEpisodes(options?: GetAiringOptions): Promise<PagedResult<AiringSchedule>>;
1009
- /** Get currently releasing manga. */
993
+ /**
994
+ * Get currently releasing manga sorted by most recently updated.
995
+ *
996
+ * @param options - Pagination parameters
997
+ */
998
+ getRecentlyUpdatedManga(options?: GetRecentChaptersOptions): Promise<PagedResult<Media>>;
999
+ /**
1000
+ * @deprecated Use `getRecentlyUpdatedManga` instead. This alias will be removed in v2.
1001
+ */
1010
1002
  getAiredChapters(options?: GetRecentChaptersOptions): Promise<PagedResult<Media>>;
1011
1003
  /** Get the detailed schedule for the current week, sorted by day. */
1012
1004
  getWeeklySchedule(date?: Date): Promise<WeeklySchedule>;
@@ -1245,19 +1237,6 @@ declare class RateLimiter {
1245
1237
  dispose(): void;
1246
1238
  }
1247
1239
 
1248
- /**
1249
- * Parses AniList specific markdown into standard HTML.
1250
- * Includes formatting for spoilers, images, videos (youtube/webm), headings,
1251
- * lists, code blocks, and standard markdown elements.
1252
- *
1253
- * @security This function escapes HTML entities to prevent XSS attacks.
1254
- * However, the output is still raw HTML — consumers should always use a
1255
- * Content Security Policy and consider additional sanitization when rendering
1256
- * user-generated content in a browser.
1257
- *
1258
- * @param text The AniList markdown text to parse
1259
- * @returns The parsed HTML string
1260
- */
1261
1240
  declare function parseAniListMarkdown(text: string): string;
1262
1241
 
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 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 };
1242
+ 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, StudioSort, type Thread, type ThreadCategory, type ThreadMediaCategory, ThreadSort, type User, type UserAvatar, type UserFavorites, UserSort, type UserStatistics, type VoiceActor, type WeeklySchedule, parseAniListMarkdown };
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  // src/utils/markdown.ts
4
+ function isSafeUrl(url) {
5
+ return /^https?:\/\//i.test(url);
6
+ }
4
7
  function parseAniListMarkdown(text) {
5
8
  if (!text) return "";
6
9
  let html = text;
@@ -11,13 +14,22 @@ function parseAniListMarkdown(text) {
11
14
  html = html.replace(/`([^`]+)`/g, "<code>$1</code>");
12
15
  html = html.replace(/~!(.*?)!~/gs, '<span class="anilist-spoiler">$1</span>');
13
16
  html = html.replace(/~~~(.*?)~~~/gs, '<div class="anilist-center">$1</div>');
14
- html = html.replace(/img(\d+)\((.*?)\)/gi, '<img src="$2" width="$1" alt="" class="anilist-image" />');
15
- html = html.replace(/img\((.*?)\)/gi, '<img src="$1" alt="" class="anilist-image" />');
16
17
  html = html.replace(
17
- /youtube\((.*?)\)/gi,
18
- '<iframe src="https://www.youtube.com/embed/$1" frameborder="0" allowfullscreen class="anilist-youtube"></iframe>'
18
+ /img(\d+)\((.*?)\)/gi,
19
+ (_match, width, url) => isSafeUrl(url) ? `<img src="${url}" width="${width}" alt="" class="anilist-image" />` : ""
20
+ );
21
+ html = html.replace(
22
+ /img\((.*?)\)/gi,
23
+ (_match, url) => isSafeUrl(url) ? `<img src="${url}" alt="" class="anilist-image" />` : ""
24
+ );
25
+ html = html.replace(/youtube\((.*?)\)/gi, (_match, id) => {
26
+ if (!/^[\w-]+$/.test(id)) return "";
27
+ return `<iframe src="https://www.youtube.com/embed/${id}" frameborder="0" allowfullscreen class="anilist-youtube"></iframe>`;
28
+ });
29
+ html = html.replace(
30
+ /webm\((.*?)\)/gi,
31
+ (_match, url) => isSafeUrl(url) ? `<video src="${url}" controls class="anilist-webm"></video>` : ""
19
32
  );
20
- html = html.replace(/webm\((.*?)\)/gi, '<video src="$1" controls class="anilist-webm"></video>');
21
33
  html = html.replace(/^######\s+(.+)$/gm, "<h6>$1</h6>");
22
34
  html = html.replace(/^#####\s+(.+)$/gm, "<h5>$1</h5>");
23
35
  html = html.replace(/^####\s+(.+)$/gm, "<h4>$1</h4>");
@@ -29,7 +41,10 @@ function parseAniListMarkdown(text) {
29
41
  html = html.replace(/_(.*?)_/g, "<em>$1</em>");
30
42
  html = html.replace(/(?<!\*)\*(?!\*)(.*?)(?<!\*)\*(?!\*)/g, "<em>$1</em>");
31
43
  html = html.replace(/~~(.*?)~~/g, "<del>$1</del>");
32
- html = html.replace(/\[(.*?)\]\((.*?)\)/g, '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>');
44
+ html = html.replace(
45
+ /\[(.*?)\]\((.*?)\)/g,
46
+ (_match, text2, url) => isSafeUrl(url) ? `<a href="${url}" target="_blank" rel="noopener noreferrer">${text2}</a>` : text2
47
+ );
33
48
  html = html.replace(/\r\n/g, "\n");
34
49
  const lines = html.split("\n");
35
50
  const processed = [];
@@ -473,6 +488,48 @@ var STUDIO_FIELDS = `
473
488
  }
474
489
  }
475
490
  `;
491
+ var THREAD_FIELDS = `
492
+ id
493
+ title
494
+ body(asHtml: false)
495
+ userId
496
+ replyUserId
497
+ replyCommentId
498
+ replyCount
499
+ viewCount
500
+ isLocked
501
+ isSticky
502
+ isSubscribed
503
+ repliedAt
504
+ createdAt
505
+ updatedAt
506
+ siteUrl
507
+ user {
508
+ id
509
+ name
510
+ avatar { large medium }
511
+ }
512
+ replyUser {
513
+ id
514
+ name
515
+ avatar { large medium }
516
+ }
517
+ categories {
518
+ id
519
+ name
520
+ }
521
+ mediaCategories {
522
+ id
523
+ title { romaji english native userPreferred }
524
+ type
525
+ coverImage { large medium }
526
+ siteUrl
527
+ }
528
+ likes {
529
+ id
530
+ name
531
+ }
532
+ `;
476
533
 
477
534
  // src/queries/media.ts
478
535
  var QUERY_MEDIA_BY_ID = `
@@ -721,10 +778,10 @@ query ($id: Int!) {
721
778
  }
722
779
  }`;
723
780
  var QUERY_STUDIO_SEARCH = `
724
- query ($search: String, $page: Int, $perPage: Int) {
781
+ query ($search: String, $sort: [StudioSort], $page: Int, $perPage: Int) {
725
782
  Page(page: $page, perPage: $perPage) {
726
783
  pageInfo { total perPage currentPage lastPage hasNextPage }
727
- studios(search: $search) {
784
+ studios(search: $search, sort: $sort) {
728
785
  ${STUDIO_FIELDS}
729
786
  }
730
787
  }
@@ -755,7 +812,7 @@ function buildMediaByIdQuery(include) {
755
812
  }
756
813
  if (include.characters) {
757
814
  const opts = typeof include.characters === "object" ? include.characters : {};
758
- const perPage = opts.perPage ?? 25;
815
+ const perPage = clampPerPage(opts.perPage ?? 25);
759
816
  const sortClause = opts.sort !== false ? ", sort: [ROLE, RELEVANCE, ID]" : "";
760
817
  const voiceActorBlock = opts.voiceActors ? `
761
818
  voiceActors {
@@ -773,7 +830,7 @@ function buildMediaByIdQuery(include) {
773
830
  }
774
831
  if (include.staff) {
775
832
  const opts = typeof include.staff === "object" ? include.staff : {};
776
- const perPage = opts.perPage ?? 25;
833
+ const perPage = clampPerPage(opts.perPage ?? 25);
777
834
  const sortClause = opts.sort !== false ? ", sort: [RELEVANCE, ID]" : "";
778
835
  extra.push(`
779
836
  staff(perPage: ${perPage}${sortClause}) {
@@ -786,7 +843,9 @@ function buildMediaByIdQuery(include) {
786
843
  }`);
787
844
  }
788
845
  if (include.recommendations) {
789
- const perPage = typeof include.recommendations === "object" ? include.recommendations.perPage ?? 10 : 10;
846
+ const perPage = clampPerPage(
847
+ typeof include.recommendations === "object" ? include.recommendations.perPage ?? 10 : 10
848
+ );
790
849
  extra.push(`
791
850
  recommendations(perPage: ${perPage}, sort: [RATING_DESC]) {
792
851
  nodes {
@@ -850,48 +909,6 @@ var buildBatchCharacterQuery = (ids) => buildBatchQuery(ids, "Character", CHARAC
850
909
  var buildBatchStaffQuery = (ids) => buildBatchQuery(ids, "Staff", STAFF_FIELDS, "s");
851
910
 
852
911
  // src/queries/thread.ts
853
- var THREAD_FIELDS = `
854
- id
855
- title
856
- body(asHtml: false)
857
- userId
858
- replyUserId
859
- replyCommentId
860
- replyCount
861
- viewCount
862
- isLocked
863
- isSticky
864
- isSubscribed
865
- repliedAt
866
- createdAt
867
- updatedAt
868
- siteUrl
869
- user {
870
- id
871
- name
872
- avatar { large medium }
873
- }
874
- replyUser {
875
- id
876
- name
877
- avatar { large medium }
878
- }
879
- categories {
880
- id
881
- name
882
- }
883
- mediaCategories {
884
- id
885
- title { romaji english native userPreferred }
886
- type
887
- coverImage { large medium }
888
- siteUrl
889
- }
890
- likes {
891
- id
892
- name
893
- }
894
- `;
895
912
  var QUERY_THREAD_BY_ID = `
896
913
  query ($id: Int!) {
897
914
  Thread(id: $id) {
@@ -1225,6 +1242,18 @@ var UserSort = /* @__PURE__ */ ((UserSort2) => {
1225
1242
  return UserSort2;
1226
1243
  })(UserSort || {});
1227
1244
 
1245
+ // src/types/studio.ts
1246
+ var StudioSort = /* @__PURE__ */ ((StudioSort2) => {
1247
+ StudioSort2["ID"] = "ID";
1248
+ StudioSort2["ID_DESC"] = "ID_DESC";
1249
+ StudioSort2["NAME"] = "NAME";
1250
+ StudioSort2["NAME_DESC"] = "NAME_DESC";
1251
+ StudioSort2["SEARCH_MATCH"] = "SEARCH_MATCH";
1252
+ StudioSort2["FAVOURITES"] = "FAVOURITES";
1253
+ StudioSort2["FAVOURITES_DESC"] = "FAVOURITES_DESC";
1254
+ return StudioSort2;
1255
+ })(StudioSort || {});
1256
+
1228
1257
  // src/types/lists.ts
1229
1258
  var MediaListStatus = /* @__PURE__ */ ((MediaListStatus2) => {
1230
1259
  MediaListStatus2["CURRENT"] = "CURRENT";
@@ -1337,7 +1366,7 @@ async function getAiredEpisodes(client, options = {}) {
1337
1366
  "airingSchedules"
1338
1367
  );
1339
1368
  }
1340
- async function getAiredChapters(client, options = {}) {
1369
+ async function getRecentlyUpdatedManga(client, options = {}) {
1341
1370
  return client.pagedRequest(
1342
1371
  QUERY_RECENT_CHAPTERS,
1343
1372
  {
@@ -1360,6 +1389,7 @@ async function getPlanning(client, options = {}) {
1360
1389
  );
1361
1390
  }
1362
1391
  async function getRecommendations(client, mediaId, options = {}) {
1392
+ validateId(mediaId, "mediaId");
1363
1393
  const data = await client.request(QUERY_RECOMMENDATIONS, {
1364
1394
  mediaId,
1365
1395
  page: options.page ?? 1,
@@ -1409,7 +1439,8 @@ async function getWeeklySchedule(client, date = /* @__PURE__ */ new Date()) {
1409
1439
  airingAtLesser: endTimestamp,
1410
1440
  page,
1411
1441
  perPage: 50
1412
- })
1442
+ }),
1443
+ 20
1413
1444
  );
1414
1445
  const names = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
1415
1446
  for await (const episode of iterator) {
@@ -1447,12 +1478,14 @@ async function getStudio(client, id) {
1447
1478
  return data.Studio;
1448
1479
  }
1449
1480
  async function searchStudios(client, options = {}) {
1481
+ const { query: search, page = 1, perPage = 20, sort } = options;
1450
1482
  return client.pagedRequest(
1451
1483
  QUERY_STUDIO_SEARCH,
1452
1484
  {
1453
- search: options.query,
1454
- page: options.page ?? 1,
1455
- perPage: clampPerPage(options.perPage ?? 20)
1485
+ search,
1486
+ sort,
1487
+ page,
1488
+ perPage: clampPerPage(perPage)
1456
1489
  },
1457
1490
  "studios"
1458
1491
  );
@@ -1498,6 +1531,9 @@ async function getUserMediaList(client, options) {
1498
1531
  if (!options.userId && !options.userName) {
1499
1532
  throw new AniListError("getUserMediaList requires either userId or userName", 0, []);
1500
1533
  }
1534
+ if (options.userId) {
1535
+ validateId(options.userId, "userId");
1536
+ }
1501
1537
  return client.pagedRequest(
1502
1538
  QUERY_USER_MEDIA_LIST,
1503
1539
  {
@@ -1537,7 +1573,7 @@ function mapFavorites(fav) {
1537
1573
 
1538
1574
  // src/client/index.ts
1539
1575
  var DEFAULT_API_URL = "https://graphql.anilist.co";
1540
- var LIB_VERSION = "1.6.1" ;
1576
+ var LIB_VERSION = "1.7.0" ;
1541
1577
  var AniListClient = class {
1542
1578
  constructor(options = {}) {
1543
1579
  this.inFlight = /* @__PURE__ */ new Map();
@@ -1682,9 +1718,19 @@ var AniListClient = class {
1682
1718
  async getAiredEpisodes(options = {}) {
1683
1719
  return getAiredEpisodes(this, options);
1684
1720
  }
1685
- /** Get currently releasing manga. */
1721
+ /**
1722
+ * Get currently releasing manga sorted by most recently updated.
1723
+ *
1724
+ * @param options - Pagination parameters
1725
+ */
1726
+ async getRecentlyUpdatedManga(options = {}) {
1727
+ return getRecentlyUpdatedManga(this, options);
1728
+ }
1729
+ /**
1730
+ * @deprecated Use `getRecentlyUpdatedManga` instead. This alias will be removed in v2.
1731
+ */
1686
1732
  async getAiredChapters(options = {}) {
1687
- return getAiredChapters(this, options);
1733
+ return this.getRecentlyUpdatedManga(options);
1688
1734
  }
1689
1735
  /** Get the detailed schedule for the current week, sorted by day. */
1690
1736
  async getWeeklySchedule(date) {
@@ -1964,6 +2010,7 @@ exports.RateLimiter = RateLimiter;
1964
2010
  exports.RecommendationSort = RecommendationSort;
1965
2011
  exports.RedisCache = RedisCache;
1966
2012
  exports.StaffSort = StaffSort;
2013
+ exports.StudioSort = StudioSort;
1967
2014
  exports.ThreadSort = ThreadSort;
1968
2015
  exports.UserSort = UserSort;
1969
2016
  exports.parseAniListMarkdown = parseAniListMarkdown;