ani-client 2.1.3 → 2.2.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
@@ -10,6 +10,8 @@
10
10
  > A fully typed, zero-dependency client for the [AniList](https://anilist.co) GraphQL API.
11
11
  > Supports Node.js, Bun, Deno, and modern browsers.
12
12
 
13
+ > 📌 **Note** – thanks for **1K+ downloads** this month on `npm` 🎉
14
+
13
15
  ## Features
14
16
 
15
17
  - **Zero dependencies** — uses the native `fetch` API
@@ -246,4 +248,4 @@ This repository also includes GitHub issue templates and a pull request template
246
248
 
247
249
  ## License
248
250
 
249
- [MIT](LICENSE) © [gonzyui](https://github.com/gonzyui)
251
+ [MIT](LICENSE) © [gonzyui](https://github.com/gonzyui)
package/dist/index.d.mts CHANGED
@@ -449,7 +449,7 @@ declare enum MediaRelationType {
449
449
  }
450
450
  interface MediaEdge {
451
451
  relationType: MediaRelationType;
452
- node: Pick<Media, "id" | "title" | "type" | "format" | "status" | "startDate" | "endDate" | "season" | "seasonYear" | "episodes" | "chapters" | "volumes" | "coverImage" | "genres" | "averageScore" | "meanScore" | "studios" | "siteUrl" | "nextAiringEpisode">;
452
+ node: Pick<Media, "id" | "title" | "type" | "format" | "status" | "description" | "startDate" | "endDate" | "season" | "seasonYear" | "episodes" | "chapters" | "volumes" | "coverImage" | "genres" | "averageScore" | "meanScore" | "studios" | "siteUrl" | "nextAiringEpisode">;
453
453
  }
454
454
  interface MediaConnection {
455
455
  edges: MediaEdge[];
@@ -490,7 +490,7 @@ interface MediaStats {
490
490
  interface MediaRecommendationNode {
491
491
  id: number;
492
492
  rating: number | null;
493
- mediaRecommendation: Pick<Media, "id" | "title" | "type" | "format" | "coverImage" | "averageScore" | "meanScore" | "episodes" | "chapters" | "volumes" | "nextAiringEpisode" | "season" | "seasonYear" | "startDate" | "endDate" | "studios" | "genres" | "siteUrl">;
493
+ mediaRecommendation: Pick<Media, "id" | "title" | "type" | "format" | "status" | "description" | "coverImage" | "averageScore" | "meanScore" | "episodes" | "chapters" | "volumes" | "nextAiringEpisode" | "season" | "seasonYear" | "startDate" | "endDate" | "studios" | "genres" | "siteUrl">;
494
494
  }
495
495
  interface NextAiringEpisode {
496
496
  id: number;
@@ -934,6 +934,7 @@ declare class NormalizedCache implements CacheAdapter {
934
934
  private _hits;
935
935
  private _misses;
936
936
  private _stales;
937
+ private gcTimeout?;
937
938
  constructor(options?: CacheOptions);
938
939
  static key(query: string, variables: Record<string, unknown>): string;
939
940
  /** Normalizes a GraphQL response, extracting entities and returning a tree of references. */
@@ -955,6 +956,7 @@ declare class NormalizedCache implements CacheAdapter {
955
956
  entitiesCount: number;
956
957
  };
957
958
  resetStats(): void;
959
+ private scheduleGc;
958
960
  /**
959
961
  * Garbage-collect orphaned entities that are no longer referenced by any query.
960
962
  * Called automatically on LRU eviction to prevent unbounded entity store growth.
@@ -1106,13 +1108,13 @@ declare class AniListClient implements ClientBase {
1106
1108
  * @param options - Search / filter parameters
1107
1109
  * @returns Paginated results with matching media
1108
1110
  */
1109
- searchMedia(options?: SearchMediaOptions): Promise<PagedResult<Media>>;
1111
+ searchMedia(options?: SearchMediaOptions, include?: MediaIncludeOptions): Promise<PagedResult<Media>>;
1110
1112
  /** Get currently trending anime or manga. */
1111
- getTrending(options?: GeneralMediaQueryOptions): Promise<PagedResult<Media>>;
1113
+ getTrending(options?: GeneralMediaQueryOptions, include?: MediaIncludeOptions): Promise<PagedResult<Media>>;
1112
1114
  /** Get the most popular anime or manga. */
1113
- getPopular(options?: GeneralMediaQueryOptions): Promise<PagedResult<Media>>;
1115
+ getPopular(options?: GeneralMediaQueryOptions, include?: MediaIncludeOptions): Promise<PagedResult<Media>>;
1114
1116
  /** Get the highest-rated anime or manga. */
1115
- getTopRated(options?: GeneralMediaQueryOptions): Promise<PagedResult<Media>>;
1117
+ getTopRated(options?: GeneralMediaQueryOptions, include?: MediaIncludeOptions): Promise<PagedResult<Media>>;
1116
1118
  /** Get recently aired anime episodes. */
1117
1119
  getAiredEpisodes(options?: GetAiringOptions): Promise<PagedResult<AiringSchedule>>;
1118
1120
  /**
@@ -1120,11 +1122,7 @@ declare class AniListClient implements ClientBase {
1120
1122
  *
1121
1123
  * @param options - Pagination parameters
1122
1124
  */
1123
- getRecentlyUpdatedManga(options?: GetRecentChaptersOptions): Promise<PagedResult<Media>>;
1124
- /**
1125
- * @deprecated Use `getRecentlyUpdatedManga()` instead. This alias will be removed in v3.
1126
- */
1127
- getAiredChapters(options?: GetRecentChaptersOptions): Promise<PagedResult<Media>>;
1125
+ getRecentlyUpdatedManga(options?: GetRecentChaptersOptions, include?: MediaIncludeOptions): Promise<PagedResult<Media>>;
1128
1126
  /**
1129
1127
  * Fetch a media entry by its MyAnimeList (MAL) ID.
1130
1128
  *
@@ -1135,11 +1133,11 @@ declare class AniListClient implements ClientBase {
1135
1133
  /** Get the detailed schedule for the current week, sorted by day. */
1136
1134
  getWeeklySchedule(date?: Date, idNotIn?: number[]): Promise<WeeklySchedule>;
1137
1135
  /** Get upcoming (not yet released) media. */
1138
- getPlanning(options?: GetPlanningOptions): Promise<PagedResult<Media>>;
1136
+ getPlanning(options?: GetPlanningOptions, include?: MediaIncludeOptions): Promise<PagedResult<Media>>;
1139
1137
  /** Get recommendations for a specific media. */
1140
1138
  getRecommendations(mediaId: number, options?: Omit<GetRecommendationsOptions, "mediaId">): Promise<PagedResult<Recommendation>>;
1141
1139
  /** Get anime (or manga) for a specific season and year. */
1142
- getMediaBySeason(options: GetSeasonOptions): Promise<PagedResult<Media>>;
1140
+ getMediaBySeason(options: GetSeasonOptions, include?: MediaIncludeOptions): Promise<PagedResult<Media>>;
1143
1141
  /** Fetch a character by AniList ID. Pass `{ voiceActors: true }` to include VA data. */
1144
1142
  getCharacter(id: number, include?: CharacterIncludeOptions): Promise<Character>;
1145
1143
  /** Search for characters by name. */
@@ -1249,6 +1247,23 @@ declare class AniListClient implements ClientBase {
1249
1247
  withSignal(signal: AbortSignal): AniListClient;
1250
1248
  }
1251
1249
 
1250
+ /**
1251
+ * Represents a location in a GraphQL query where an error occurred.
1252
+ */
1253
+ interface GraphQLErrorLocation {
1254
+ line: number;
1255
+ column: number;
1256
+ }
1257
+ /**
1258
+ * Standard GraphQL error shape.
1259
+ */
1260
+ interface GraphQLError {
1261
+ message: string;
1262
+ locations?: GraphQLErrorLocation[];
1263
+ path?: (string | number)[];
1264
+ extensions?: Record<string, unknown>;
1265
+ [key: string]: unknown;
1266
+ }
1252
1267
  /**
1253
1268
  * Custom error class for AniList API errors.
1254
1269
  */
@@ -1256,8 +1271,8 @@ declare class AniListError extends Error {
1256
1271
  /** HTTP status code returned by the API */
1257
1272
  readonly status: number;
1258
1273
  /** Raw error body from the API response */
1259
- readonly errors: unknown[];
1260
- constructor(message: string, status: number, errors?: unknown[]);
1274
+ readonly errors: GraphQLError[];
1275
+ constructor(message: string, status: number, errors?: GraphQLError[] | unknown[]);
1261
1276
  }
1262
1277
 
1263
1278
  /**
package/dist/index.d.ts CHANGED
@@ -449,7 +449,7 @@ declare enum MediaRelationType {
449
449
  }
450
450
  interface MediaEdge {
451
451
  relationType: MediaRelationType;
452
- node: Pick<Media, "id" | "title" | "type" | "format" | "status" | "startDate" | "endDate" | "season" | "seasonYear" | "episodes" | "chapters" | "volumes" | "coverImage" | "genres" | "averageScore" | "meanScore" | "studios" | "siteUrl" | "nextAiringEpisode">;
452
+ node: Pick<Media, "id" | "title" | "type" | "format" | "status" | "description" | "startDate" | "endDate" | "season" | "seasonYear" | "episodes" | "chapters" | "volumes" | "coverImage" | "genres" | "averageScore" | "meanScore" | "studios" | "siteUrl" | "nextAiringEpisode">;
453
453
  }
454
454
  interface MediaConnection {
455
455
  edges: MediaEdge[];
@@ -490,7 +490,7 @@ interface MediaStats {
490
490
  interface MediaRecommendationNode {
491
491
  id: number;
492
492
  rating: number | null;
493
- mediaRecommendation: Pick<Media, "id" | "title" | "type" | "format" | "coverImage" | "averageScore" | "meanScore" | "episodes" | "chapters" | "volumes" | "nextAiringEpisode" | "season" | "seasonYear" | "startDate" | "endDate" | "studios" | "genres" | "siteUrl">;
493
+ mediaRecommendation: Pick<Media, "id" | "title" | "type" | "format" | "status" | "description" | "coverImage" | "averageScore" | "meanScore" | "episodes" | "chapters" | "volumes" | "nextAiringEpisode" | "season" | "seasonYear" | "startDate" | "endDate" | "studios" | "genres" | "siteUrl">;
494
494
  }
495
495
  interface NextAiringEpisode {
496
496
  id: number;
@@ -934,6 +934,7 @@ declare class NormalizedCache implements CacheAdapter {
934
934
  private _hits;
935
935
  private _misses;
936
936
  private _stales;
937
+ private gcTimeout?;
937
938
  constructor(options?: CacheOptions);
938
939
  static key(query: string, variables: Record<string, unknown>): string;
939
940
  /** Normalizes a GraphQL response, extracting entities and returning a tree of references. */
@@ -955,6 +956,7 @@ declare class NormalizedCache implements CacheAdapter {
955
956
  entitiesCount: number;
956
957
  };
957
958
  resetStats(): void;
959
+ private scheduleGc;
958
960
  /**
959
961
  * Garbage-collect orphaned entities that are no longer referenced by any query.
960
962
  * Called automatically on LRU eviction to prevent unbounded entity store growth.
@@ -1106,13 +1108,13 @@ declare class AniListClient implements ClientBase {
1106
1108
  * @param options - Search / filter parameters
1107
1109
  * @returns Paginated results with matching media
1108
1110
  */
1109
- searchMedia(options?: SearchMediaOptions): Promise<PagedResult<Media>>;
1111
+ searchMedia(options?: SearchMediaOptions, include?: MediaIncludeOptions): Promise<PagedResult<Media>>;
1110
1112
  /** Get currently trending anime or manga. */
1111
- getTrending(options?: GeneralMediaQueryOptions): Promise<PagedResult<Media>>;
1113
+ getTrending(options?: GeneralMediaQueryOptions, include?: MediaIncludeOptions): Promise<PagedResult<Media>>;
1112
1114
  /** Get the most popular anime or manga. */
1113
- getPopular(options?: GeneralMediaQueryOptions): Promise<PagedResult<Media>>;
1115
+ getPopular(options?: GeneralMediaQueryOptions, include?: MediaIncludeOptions): Promise<PagedResult<Media>>;
1114
1116
  /** Get the highest-rated anime or manga. */
1115
- getTopRated(options?: GeneralMediaQueryOptions): Promise<PagedResult<Media>>;
1117
+ getTopRated(options?: GeneralMediaQueryOptions, include?: MediaIncludeOptions): Promise<PagedResult<Media>>;
1116
1118
  /** Get recently aired anime episodes. */
1117
1119
  getAiredEpisodes(options?: GetAiringOptions): Promise<PagedResult<AiringSchedule>>;
1118
1120
  /**
@@ -1120,11 +1122,7 @@ declare class AniListClient implements ClientBase {
1120
1122
  *
1121
1123
  * @param options - Pagination parameters
1122
1124
  */
1123
- getRecentlyUpdatedManga(options?: GetRecentChaptersOptions): Promise<PagedResult<Media>>;
1124
- /**
1125
- * @deprecated Use `getRecentlyUpdatedManga()` instead. This alias will be removed in v3.
1126
- */
1127
- getAiredChapters(options?: GetRecentChaptersOptions): Promise<PagedResult<Media>>;
1125
+ getRecentlyUpdatedManga(options?: GetRecentChaptersOptions, include?: MediaIncludeOptions): Promise<PagedResult<Media>>;
1128
1126
  /**
1129
1127
  * Fetch a media entry by its MyAnimeList (MAL) ID.
1130
1128
  *
@@ -1135,11 +1133,11 @@ declare class AniListClient implements ClientBase {
1135
1133
  /** Get the detailed schedule for the current week, sorted by day. */
1136
1134
  getWeeklySchedule(date?: Date, idNotIn?: number[]): Promise<WeeklySchedule>;
1137
1135
  /** Get upcoming (not yet released) media. */
1138
- getPlanning(options?: GetPlanningOptions): Promise<PagedResult<Media>>;
1136
+ getPlanning(options?: GetPlanningOptions, include?: MediaIncludeOptions): Promise<PagedResult<Media>>;
1139
1137
  /** Get recommendations for a specific media. */
1140
1138
  getRecommendations(mediaId: number, options?: Omit<GetRecommendationsOptions, "mediaId">): Promise<PagedResult<Recommendation>>;
1141
1139
  /** Get anime (or manga) for a specific season and year. */
1142
- getMediaBySeason(options: GetSeasonOptions): Promise<PagedResult<Media>>;
1140
+ getMediaBySeason(options: GetSeasonOptions, include?: MediaIncludeOptions): Promise<PagedResult<Media>>;
1143
1141
  /** Fetch a character by AniList ID. Pass `{ voiceActors: true }` to include VA data. */
1144
1142
  getCharacter(id: number, include?: CharacterIncludeOptions): Promise<Character>;
1145
1143
  /** Search for characters by name. */
@@ -1249,6 +1247,23 @@ declare class AniListClient implements ClientBase {
1249
1247
  withSignal(signal: AbortSignal): AniListClient;
1250
1248
  }
1251
1249
 
1250
+ /**
1251
+ * Represents a location in a GraphQL query where an error occurred.
1252
+ */
1253
+ interface GraphQLErrorLocation {
1254
+ line: number;
1255
+ column: number;
1256
+ }
1257
+ /**
1258
+ * Standard GraphQL error shape.
1259
+ */
1260
+ interface GraphQLError {
1261
+ message: string;
1262
+ locations?: GraphQLErrorLocation[];
1263
+ path?: (string | number)[];
1264
+ extensions?: Record<string, unknown>;
1265
+ [key: string]: unknown;
1266
+ }
1252
1267
  /**
1253
1268
  * Custom error class for AniList API errors.
1254
1269
  */
@@ -1256,8 +1271,8 @@ declare class AniListError extends Error {
1256
1271
  /** HTTP status code returned by the API */
1257
1272
  readonly status: number;
1258
1273
  /** Raw error body from the API response */
1259
- readonly errors: unknown[];
1260
- constructor(message: string, status: number, errors?: unknown[]);
1274
+ readonly errors: GraphQLError[];
1275
+ constructor(message: string, status: number, errors?: GraphQLError[] | unknown[]);
1261
1276
  }
1262
1277
 
1263
1278
  /**
package/dist/index.js CHANGED
@@ -135,6 +135,7 @@ var NormalizedCache = class {
135
135
  _hits = 0;
136
136
  _misses = 0;
137
137
  _stales = 0;
138
+ gcTimeout;
138
139
  constructor(options = {}) {
139
140
  this.ttl = options.ttl ?? 24 * 60 * 60 * 1e3;
140
141
  this.maxSize = options.maxSize ?? 500;
@@ -246,8 +247,10 @@ var NormalizedCache = class {
246
247
  this.queryStore.delete(key);
247
248
  if (this.maxSize > 0 && this.queryStore.size >= this.maxSize) {
248
249
  const firstKey = this.queryStore.keys().next().value;
249
- if (firstKey !== void 0) this.queryStore.delete(firstKey);
250
- this.gc();
250
+ if (firstKey !== void 0) {
251
+ this.queryStore.delete(firstKey);
252
+ }
253
+ this.scheduleGc();
251
254
  }
252
255
  this.queryStore.set(key, { data: normalizedData, expiresAt: Date.now() + this.ttl });
253
256
  }
@@ -255,6 +258,10 @@ var NormalizedCache = class {
255
258
  return this.queryStore.delete(key);
256
259
  }
257
260
  clear() {
261
+ if (this.gcTimeout) {
262
+ clearTimeout(this.gcTimeout);
263
+ this.gcTimeout = void 0;
264
+ }
258
265
  this.queryStore.clear();
259
266
  this.entityStore.clear();
260
267
  this._hits = 0;
@@ -291,6 +298,16 @@ var NormalizedCache = class {
291
298
  this._misses = 0;
292
299
  this._stales = 0;
293
300
  }
301
+ scheduleGc() {
302
+ if (this.gcTimeout) return;
303
+ this.gcTimeout = setTimeout(() => {
304
+ this.gc();
305
+ this.gcTimeout = void 0;
306
+ }, 500);
307
+ if (typeof this.gcTimeout.unref === "function") {
308
+ this.gcTimeout.unref();
309
+ }
310
+ }
294
311
  /**
295
312
  * Garbage-collect orphaned entities that are no longer referenced by any query.
296
313
  * Called automatically on LRU eviction to prevent unbounded entity store growth.
@@ -649,6 +666,7 @@ var RELATIONS_FIELDS = `
649
666
  type
650
667
  format
651
668
  status
669
+ description(asHtml: false)
652
670
  startDate { year month day }
653
671
  endDate { year month day }
654
672
  season
@@ -683,6 +701,8 @@ var MEDIA_RECOMMENDATION_FIELDS = `
683
701
  title { romaji english native userPreferred }
684
702
  type
685
703
  format
704
+ status
705
+ description(asHtml: false)
686
706
  coverImage { extraLarge large medium color }
687
707
  averageScore
688
708
  meanScore
@@ -1180,8 +1200,7 @@ query ($mediaId: Int!, $page: Int, $perPage: Int, $sort: [RecommendationSort]) {
1180
1200
  }`;
1181
1201
 
1182
1202
  // src/queries/builders.ts
1183
- function buildMediaByIdQuery(include) {
1184
- if (!include) return QUERY_MEDIA_BY_ID;
1203
+ function buildMediaIncludeQuery(include) {
1185
1204
  const extra = [];
1186
1205
  if (include.relations !== false) {
1187
1206
  extra.push(RELATIONS_FIELDS);
@@ -1256,14 +1275,172 @@ function buildMediaByIdQuery(include) {
1256
1275
  statusDistribution { status amount }
1257
1276
  }`);
1258
1277
  }
1278
+ return extra;
1279
+ }
1280
+ function buildMediaByIdQuery(include) {
1281
+ if (!include) return QUERY_MEDIA_BY_ID;
1259
1282
  return `
1260
1283
  query ($id: Int!) {
1261
1284
  Media(id: $id) {
1262
1285
  ${MEDIA_FIELDS_BASE}
1263
- ${extra.join("\n")}
1286
+ ${buildMediaIncludeQuery(include).join("\n")}
1264
1287
  }
1265
1288
  }`;
1266
1289
  }
1290
+ function buildSearchMediaQuery(include) {
1291
+ if (!include) return QUERY_MEDIA_SEARCH;
1292
+ return `
1293
+ query (
1294
+ $search: String,
1295
+ $countryOfOrigin: CountryCode,
1296
+ $type: MediaType,
1297
+ $format: MediaFormat,
1298
+ $format_in: [MediaFormat],
1299
+ $status: MediaStatus,
1300
+ $season: MediaSeason,
1301
+ $seasonYear: Int,
1302
+ $genre: String,
1303
+ $tag: String,
1304
+ $genre_in: [String],
1305
+ $tag_in: [String],
1306
+ $genre_not_in: [String],
1307
+ $tag_not_in: [String],
1308
+ $isAdult: Boolean,
1309
+ $idNotIn: [Int],
1310
+ $sort: [MediaSort],
1311
+ $page: Int,
1312
+ $perPage: Int
1313
+ ) {
1314
+ Page(page: $page, perPage: $perPage) {
1315
+ pageInfo { total perPage currentPage lastPage hasNextPage }
1316
+ media(
1317
+ search: $search,
1318
+ countryOfOrigin: $countryOfOrigin,
1319
+ type: $type,
1320
+ format: $format,
1321
+ format_in: $format_in,
1322
+ status: $status,
1323
+ season: $season,
1324
+ seasonYear: $seasonYear,
1325
+ genre: $genre,
1326
+ tag: $tag,
1327
+ genre_in: $genre_in,
1328
+ tag_in: $tag_in,
1329
+ genre_not_in: $genre_not_in,
1330
+ tag_not_in: $tag_not_in,
1331
+ isAdult: $isAdult,
1332
+ id_not_in: $idNotIn,
1333
+ sort: $sort
1334
+ ) {
1335
+ ${MEDIA_FIELDS_BASE}
1336
+ ${buildMediaIncludeQuery(include).join("\n")}
1337
+ }
1338
+ }
1339
+ }`;
1340
+ }
1341
+ function buildGetTrendingQuery(include) {
1342
+ if (!include) return QUERY_TRENDING;
1343
+ return `
1344
+ query (
1345
+ $type: MediaType,
1346
+ $isAdult: Boolean,
1347
+ $idNotIn: [Int],
1348
+ $page: Int,
1349
+ $perPage: Int
1350
+ ) {
1351
+ Page(page: $page, perPage: $perPage) {
1352
+ pageInfo { total perPage currentPage lastPage hasNextPage }
1353
+ media(
1354
+ type: $type,
1355
+ isAdult: $isAdult,
1356
+ id_not_in: $idNotIn,
1357
+ sort: TRENDING_DESC
1358
+ ) {
1359
+ ${MEDIA_FIELDS_BASE}
1360
+ ${buildMediaIncludeQuery(include).join("\n")}
1361
+ }
1362
+ }
1363
+ }`;
1364
+ }
1365
+ function buildGetMediaBySeasonQuery(include) {
1366
+ if (!include) return QUERY_MEDIA_BY_SEASON;
1367
+ return `
1368
+ query (
1369
+ $season: MediaSeason!,
1370
+ $seasonYear: Int!,
1371
+ $type: MediaType,
1372
+ $isAdult: Boolean,
1373
+ $idNotIn: [Int],
1374
+ $sort: [MediaSort],
1375
+ $page: Int,
1376
+ $perPage: Int
1377
+ ) {
1378
+ Page(page: $page, perPage: $perPage) {
1379
+ pageInfo { total perPage currentPage lastPage hasNextPage }
1380
+ media(
1381
+ season: $season,
1382
+ seasonYear: $seasonYear,
1383
+ type: $type,
1384
+ isAdult: $isAdult,
1385
+ id_not_in: $idNotIn,
1386
+ sort: $sort
1387
+ ) {
1388
+ ${MEDIA_FIELDS_BASE}
1389
+ ${buildMediaIncludeQuery(include).join("\n")}
1390
+ }
1391
+ }
1392
+ }`;
1393
+ }
1394
+ function buildGetRecentlyUpdatedMangaQuery(include) {
1395
+ if (!include) return QUERY_RECENT_CHAPTERS;
1396
+ return `
1397
+ query (
1398
+ $isAdult: Boolean,
1399
+ $idNotIn: [Int],
1400
+ $page: Int,
1401
+ $perPage: Int
1402
+ ) {
1403
+ Page(page: $page, perPage: $perPage) {
1404
+ pageInfo { total perPage currentPage lastPage hasNextPage }
1405
+ media(
1406
+ type: MANGA,
1407
+ isAdult: $isAdult,
1408
+ id_not_in: $idNotIn,
1409
+ status: RELEASING,
1410
+ sort: UPDATED_AT_DESC
1411
+ ) {
1412
+ ${MEDIA_FIELDS_BASE}
1413
+ ${buildMediaIncludeQuery(include).join("\n")}
1414
+ }
1415
+ }
1416
+ }`;
1417
+ }
1418
+ function buildGetPlanningQuery(include) {
1419
+ if (!include) return QUERY_PLANNING;
1420
+ return `
1421
+ query (
1422
+ $type: MediaType,
1423
+ $isAdult: Boolean,
1424
+ $idNotIn: [Int],
1425
+ $sort: [MediaSort],
1426
+ $page: Int,
1427
+ $perPage: Int
1428
+ ) {
1429
+ Page(page: $page, perPage: $perPage) {
1430
+ pageInfo { total perPage currentPage lastPage hasNextPage }
1431
+ media(
1432
+ type: $type,
1433
+ isAdult: $isAdult,
1434
+ id_not_in: $idNotIn,
1435
+ status: NOT_YET_RELEASED,
1436
+ sort: $sort
1437
+ ) {
1438
+ ${MEDIA_FIELDS_BASE}
1439
+ ${buildMediaIncludeQuery(include).join("\n")}
1440
+ }
1441
+ }
1442
+ }`;
1443
+ }
1267
1444
  function buildMediaCharactersQuery(options = {}) {
1268
1445
  const sortClause = options.sort === false ? "" : ", sort: [ROLE, RELEVANCE, ID]";
1269
1446
  const voiceActorBlock = options.voiceActors ? `
@@ -2065,7 +2242,7 @@ async function getMediaByMalId(client, malId, type) {
2065
2242
  });
2066
2243
  return data.Media;
2067
2244
  }
2068
- async function searchMedia(client, options = {}) {
2245
+ async function searchMedia(client, options = {}, include) {
2069
2246
  const {
2070
2247
  query: search,
2071
2248
  page = 1,
@@ -2077,8 +2254,9 @@ async function searchMedia(client, options = {}) {
2077
2254
  format,
2078
2255
  ...filters
2079
2256
  } = options;
2257
+ const query = buildSearchMediaQuery(include);
2080
2258
  return client.pagedRequest(
2081
- QUERY_MEDIA_SEARCH,
2259
+ query,
2082
2260
  {
2083
2261
  search,
2084
2262
  ...filters,
@@ -2094,21 +2272,18 @@ async function searchMedia(client, options = {}) {
2094
2272
  "media"
2095
2273
  );
2096
2274
  }
2097
- async function getTrending(client, options) {
2275
+ async function getTrending(client, options, include) {
2098
2276
  const { type = "ANIME" /* ANIME */, isAdult = false, idNotIn = [], page = 1, perPage = 20 } = options;
2099
- return client.pagedRequest(
2100
- QUERY_TRENDING,
2101
- { type, isAdult, idNotIn, page, perPage: clampPerPage(perPage) },
2102
- "media"
2103
- );
2277
+ const query = buildGetTrendingQuery(include);
2278
+ return client.pagedRequest(query, { type, isAdult, idNotIn, page, perPage: clampPerPage(perPage) }, "media");
2104
2279
  }
2105
- async function getPopular(client, options) {
2280
+ async function getPopular(client, options, include) {
2106
2281
  const { type = "ANIME" /* ANIME */, isAdult = false, idNotIn = [], page = 1, perPage = 20 } = options;
2107
- return searchMedia(client, { type, isAdult, idNotIn, sort: ["POPULARITY_DESC" /* POPULARITY_DESC */], page, perPage });
2282
+ return searchMedia(client, { type, isAdult, idNotIn, sort: ["POPULARITY_DESC" /* POPULARITY_DESC */], page, perPage }, include);
2108
2283
  }
2109
- async function getTopRated(client, options) {
2284
+ async function getTopRated(client, options, include) {
2110
2285
  const { type = "ANIME" /* ANIME */, isAdult = false, idNotIn = [], page = 1, perPage = 20 } = options;
2111
- return searchMedia(client, { type, isAdult, idNotIn, sort: ["SCORE_DESC" /* SCORE_DESC */], page, perPage });
2286
+ return searchMedia(client, { type, isAdult, idNotIn, sort: ["SCORE_DESC" /* SCORE_DESC */], page, perPage }, include);
2112
2287
  }
2113
2288
  async function getAiredEpisodes(client, options = {}) {
2114
2289
  const now = Math.floor(Date.now() / 1e3);
@@ -2125,9 +2300,10 @@ async function getAiredEpisodes(client, options = {}) {
2125
2300
  "airingSchedules"
2126
2301
  );
2127
2302
  }
2128
- async function getRecentlyUpdatedManga(client, options = {}) {
2303
+ async function getRecentlyUpdatedManga(client, options = {}, include) {
2304
+ const query = buildGetRecentlyUpdatedMangaQuery(include);
2129
2305
  return client.pagedRequest(
2130
- QUERY_RECENT_CHAPTERS,
2306
+ query,
2131
2307
  {
2132
2308
  isAdult: options.isAdult ?? false,
2133
2309
  idNotIn: options.idNotIn ?? [],
@@ -2137,9 +2313,10 @@ async function getRecentlyUpdatedManga(client, options = {}) {
2137
2313
  "media"
2138
2314
  );
2139
2315
  }
2140
- async function getPlanning(client, options = {}) {
2316
+ async function getPlanning(client, options = {}, include) {
2317
+ const query = buildGetPlanningQuery(include);
2141
2318
  return client.pagedRequest(
2142
- QUERY_PLANNING,
2319
+ query,
2143
2320
  {
2144
2321
  type: options.type,
2145
2322
  isAdult: options.isAdult ?? false,
@@ -2164,9 +2341,10 @@ async function getRecommendations(client, mediaId, options = {}) {
2164
2341
  results: data.Media.recommendations.nodes
2165
2342
  };
2166
2343
  }
2167
- async function getMediaBySeason(client, options) {
2344
+ async function getMediaBySeason(client, options, include) {
2345
+ const query = buildGetMediaBySeasonQuery(include);
2168
2346
  return client.pagedRequest(
2169
- QUERY_MEDIA_BY_SEASON,
2347
+ query,
2170
2348
  {
2171
2349
  season: options.season,
2172
2350
  seasonYear: options.seasonYear,
@@ -2363,7 +2541,7 @@ function mapFavorites(fav) {
2363
2541
 
2364
2542
  // src/client/index.ts
2365
2543
  var DEFAULT_API_URL = "https://graphql.anilist.co";
2366
- var LIB_VERSION = "2.1.3" ;
2544
+ var LIB_VERSION = "2.2.0" ;
2367
2545
  var AniListClient = class {
2368
2546
  apiUrl;
2369
2547
  headers;
@@ -2533,20 +2711,20 @@ var AniListClient = class {
2533
2711
  * @param options - Search / filter parameters
2534
2712
  * @returns Paginated results with matching media
2535
2713
  */
2536
- async searchMedia(options = {}) {
2537
- return searchMedia(this, options);
2714
+ async searchMedia(options = {}, include) {
2715
+ return searchMedia(this, options, include);
2538
2716
  }
2539
2717
  /** Get currently trending anime or manga. */
2540
- async getTrending(options = {}) {
2541
- return getTrending(this, options);
2718
+ async getTrending(options = {}, include) {
2719
+ return getTrending(this, options, include);
2542
2720
  }
2543
2721
  /** Get the most popular anime or manga. */
2544
- async getPopular(options = {}) {
2545
- return getPopular(this, options);
2722
+ async getPopular(options = {}, include) {
2723
+ return getPopular(this, options, include);
2546
2724
  }
2547
2725
  /** Get the highest-rated anime or manga. */
2548
- async getTopRated(options = {}) {
2549
- return getTopRated(this, options);
2726
+ async getTopRated(options = {}, include) {
2727
+ return getTopRated(this, options, include);
2550
2728
  }
2551
2729
  /** Get recently aired anime episodes. */
2552
2730
  async getAiredEpisodes(options = {}) {
@@ -2557,14 +2735,8 @@ var AniListClient = class {
2557
2735
  *
2558
2736
  * @param options - Pagination parameters
2559
2737
  */
2560
- async getRecentlyUpdatedManga(options = {}) {
2561
- return getRecentlyUpdatedManga(this, options);
2562
- }
2563
- /**
2564
- * @deprecated Use `getRecentlyUpdatedManga()` instead. This alias will be removed in v3.
2565
- */
2566
- async getAiredChapters(options = {}) {
2567
- return this.getRecentlyUpdatedManga(options);
2738
+ async getRecentlyUpdatedManga(options = {}, include) {
2739
+ return getRecentlyUpdatedManga(this, options, include);
2568
2740
  }
2569
2741
  /**
2570
2742
  * Fetch a media entry by its MyAnimeList (MAL) ID.
@@ -2580,16 +2752,16 @@ var AniListClient = class {
2580
2752
  return getWeeklySchedule(this, date, idNotIn);
2581
2753
  }
2582
2754
  /** Get upcoming (not yet released) media. */
2583
- async getPlanning(options = {}) {
2584
- return getPlanning(this, options);
2755
+ async getPlanning(options = {}, include) {
2756
+ return getPlanning(this, options, include);
2585
2757
  }
2586
2758
  /** Get recommendations for a specific media. */
2587
2759
  async getRecommendations(mediaId, options = {}) {
2588
2760
  return getRecommendations(this, mediaId, options);
2589
2761
  }
2590
2762
  /** Get anime (or manga) for a specific season and year. */
2591
- async getMediaBySeason(options) {
2592
- return getMediaBySeason(this, options);
2763
+ async getMediaBySeason(options, include) {
2764
+ return getMediaBySeason(this, options, include);
2593
2765
  }
2594
2766
  /** Fetch a character by AniList ID. Pass `{ voiceActors: true }` to include VA data. */
2595
2767
  async getCharacter(id, include) {