ani-client 1.4.2 → 1.4.3

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.mjs CHANGED
@@ -627,6 +627,7 @@ var AniListError = class _AniListError extends Error {
627
627
  this.name = "AniListError";
628
628
  this.status = status;
629
629
  this.errors = errors;
630
+ Object.setPrototypeOf(this, _AniListError.prototype);
630
631
  if (Error.captureStackTrace) {
631
632
  Error.captureStackTrace(this, _AniListError);
632
633
  }
@@ -728,7 +729,7 @@ function isNetworkError(err) {
728
729
  return false;
729
730
  }
730
731
 
731
- // src/types/index.ts
732
+ // src/types/media.ts
732
733
  var MediaType = /* @__PURE__ */ ((MediaType2) => {
733
734
  MediaType2["ANIME"] = "ANIME";
734
735
  MediaType2["MANGA"] = "MANGA";
@@ -809,22 +810,6 @@ var AiringSort = /* @__PURE__ */ ((AiringSort2) => {
809
810
  AiringSort2["EPISODE_DESC"] = "EPISODE_DESC";
810
811
  return AiringSort2;
811
812
  })(AiringSort || {});
812
- var CharacterSort = /* @__PURE__ */ ((CharacterSort2) => {
813
- CharacterSort2["ID"] = "ID";
814
- CharacterSort2["ID_DESC"] = "ID_DESC";
815
- CharacterSort2["ROLE"] = "ROLE";
816
- CharacterSort2["ROLE_DESC"] = "ROLE_DESC";
817
- CharacterSort2["SEARCH_MATCH"] = "SEARCH_MATCH";
818
- CharacterSort2["FAVOURITES"] = "FAVOURITES";
819
- CharacterSort2["FAVOURITES_DESC"] = "FAVOURITES_DESC";
820
- return CharacterSort2;
821
- })(CharacterSort || {});
822
- var CharacterRole = /* @__PURE__ */ ((CharacterRole2) => {
823
- CharacterRole2["MAIN"] = "MAIN";
824
- CharacterRole2["SUPPORTING"] = "SUPPORTING";
825
- CharacterRole2["BACKGROUND"] = "BACKGROUND";
826
- return CharacterRole2;
827
- })(CharacterRole || {});
828
813
  var MediaRelationType = /* @__PURE__ */ ((MediaRelationType2) => {
829
814
  MediaRelationType2["ADAPTATION"] = "ADAPTATION";
830
815
  MediaRelationType2["PREQUEL"] = "PREQUEL";
@@ -848,6 +833,26 @@ var RecommendationSort = /* @__PURE__ */ ((RecommendationSort2) => {
848
833
  RecommendationSort2["RATING_DESC"] = "RATING_DESC";
849
834
  return RecommendationSort2;
850
835
  })(RecommendationSort || {});
836
+
837
+ // src/types/character.ts
838
+ var CharacterSort = /* @__PURE__ */ ((CharacterSort2) => {
839
+ CharacterSort2["ID"] = "ID";
840
+ CharacterSort2["ID_DESC"] = "ID_DESC";
841
+ CharacterSort2["ROLE"] = "ROLE";
842
+ CharacterSort2["ROLE_DESC"] = "ROLE_DESC";
843
+ CharacterSort2["SEARCH_MATCH"] = "SEARCH_MATCH";
844
+ CharacterSort2["FAVOURITES"] = "FAVOURITES";
845
+ CharacterSort2["FAVOURITES_DESC"] = "FAVOURITES_DESC";
846
+ return CharacterSort2;
847
+ })(CharacterSort || {});
848
+ var CharacterRole = /* @__PURE__ */ ((CharacterRole2) => {
849
+ CharacterRole2["MAIN"] = "MAIN";
850
+ CharacterRole2["SUPPORTING"] = "SUPPORTING";
851
+ CharacterRole2["BACKGROUND"] = "BACKGROUND";
852
+ return CharacterRole2;
853
+ })(CharacterRole || {});
854
+
855
+ // src/types/lists.ts
851
856
  var MediaListStatus = /* @__PURE__ */ ((MediaListStatus2) => {
852
857
  MediaListStatus2["CURRENT"] = "CURRENT";
853
858
  MediaListStatus2["PLANNING"] = "PLANNING";
@@ -891,6 +896,18 @@ var MediaListSort = /* @__PURE__ */ ((MediaListSort2) => {
891
896
  return MediaListSort2;
892
897
  })(MediaListSort || {});
893
898
 
899
+ // src/utils/index.ts
900
+ function clampPerPage(value) {
901
+ return Math.min(Math.max(value, 1), 50);
902
+ }
903
+ function chunk(arr, size) {
904
+ const chunks = [];
905
+ for (let i = 0; i < arr.length; i += size) {
906
+ chunks.push(arr.slice(i, i + size));
907
+ }
908
+ return chunks;
909
+ }
910
+
894
911
  // src/client/index.ts
895
912
  var DEFAULT_API_URL = "https://graphql.anilist.co";
896
913
  var AniListClient = class {
@@ -933,12 +950,13 @@ var AniListClient = class {
933
950
  async executeRequest(query, variables, cacheKey) {
934
951
  const start = Date.now();
935
952
  this.hooks.onRequest?.(query, variables);
953
+ const minifiedQuery = query.replace(/\s+/g, " ").trim();
936
954
  const res = await this.rateLimiter.fetchWithRetry(
937
955
  this.apiUrl,
938
956
  {
939
957
  method: "POST",
940
958
  headers: this.headers,
941
- body: JSON.stringify({ query, variables })
959
+ body: JSON.stringify({ query: minifiedQuery, variables })
942
960
  },
943
961
  { onRetry: this.hooks.onRetry, onRateLimit: this.hooks.onRateLimit }
944
962
  );
@@ -964,13 +982,6 @@ var AniListClient = class {
964
982
  }
965
983
  return { pageInfo: data.Page.pageInfo, results };
966
984
  }
967
- /**
968
- * @internal
969
- * Clamp perPage to AniList's maximum of 50.
970
- */
971
- clampPerPage(value) {
972
- return Math.min(Math.max(value, 1), 50);
973
- }
974
985
  /**
975
986
  * Fetch a single media entry by its AniList ID.
976
987
  *
@@ -1030,7 +1041,7 @@ var AniListClient = class {
1030
1041
  const { query: search, page = 1, perPage = 20, ...filters } = options;
1031
1042
  return this.pagedRequest(
1032
1043
  QUERY_MEDIA_SEARCH,
1033
- { search, ...filters, page, perPage: this.clampPerPage(perPage) },
1044
+ { search, ...filters, page, perPage: clampPerPage(perPage) },
1034
1045
  "media"
1035
1046
  );
1036
1047
  }
@@ -1042,7 +1053,7 @@ var AniListClient = class {
1042
1053
  * @param perPage - Results per page (default 20, max 50)
1043
1054
  */
1044
1055
  async getTrending(type = "ANIME" /* ANIME */, page = 1, perPage = 20) {
1045
- return this.pagedRequest(QUERY_TRENDING, { type, page, perPage: this.clampPerPage(perPage) }, "media");
1056
+ return this.pagedRequest(QUERY_TRENDING, { type, page, perPage: clampPerPage(perPage) }, "media");
1046
1057
  }
1047
1058
  /**
1048
1059
  * Fetch a character by AniList ID.
@@ -1088,7 +1099,7 @@ var AniListClient = class {
1088
1099
  const gqlQuery = voiceActors ? QUERY_CHARACTER_SEARCH_WITH_VA : QUERY_CHARACTER_SEARCH;
1089
1100
  return this.pagedRequest(
1090
1101
  gqlQuery,
1091
- { search, ...rest, page, perPage: this.clampPerPage(perPage) },
1102
+ { search, ...rest, page, perPage: clampPerPage(perPage) },
1092
1103
  "characters"
1093
1104
  );
1094
1105
  }
@@ -1134,7 +1145,7 @@ var AniListClient = class {
1134
1145
  const { query: search, page = 1, perPage = 20, sort } = options;
1135
1146
  return this.pagedRequest(
1136
1147
  QUERY_STAFF_SEARCH,
1137
- { search, sort, page, perPage: this.clampPerPage(perPage) },
1148
+ { search, sort, page, perPage: clampPerPage(perPage) },
1138
1149
  "staff"
1139
1150
  );
1140
1151
  }
@@ -1203,7 +1214,7 @@ var AniListClient = class {
1203
1214
  airingAt_lesser: options.airingAtLesser ?? now,
1204
1215
  sort: options.sort ?? ["TIME_DESC"],
1205
1216
  page: options.page ?? 1,
1206
- perPage: this.clampPerPage(options.perPage ?? 20)
1217
+ perPage: clampPerPage(options.perPage ?? 20)
1207
1218
  };
1208
1219
  return this.pagedRequest(QUERY_AIRING_SCHEDULE, variables, "airingSchedules");
1209
1220
  }
@@ -1226,7 +1237,7 @@ var AniListClient = class {
1226
1237
  QUERY_RECENT_CHAPTERS,
1227
1238
  {
1228
1239
  page: options.page ?? 1,
1229
- perPage: this.clampPerPage(options.perPage ?? 20)
1240
+ perPage: clampPerPage(options.perPage ?? 20)
1230
1241
  },
1231
1242
  "media"
1232
1243
  );
@@ -1252,7 +1263,7 @@ var AniListClient = class {
1252
1263
  type: options.type,
1253
1264
  sort: options.sort ?? ["POPULARITY_DESC"],
1254
1265
  page: options.page ?? 1,
1255
- perPage: this.clampPerPage(options.perPage ?? 20)
1266
+ perPage: clampPerPage(options.perPage ?? 20)
1256
1267
  },
1257
1268
  "media"
1258
1269
  );
@@ -1314,7 +1325,7 @@ var AniListClient = class {
1314
1325
  type: options.type ?? "ANIME",
1315
1326
  sort: options.sort ?? ["POPULARITY_DESC"],
1316
1327
  page: options.page ?? 1,
1317
- perPage: this.clampPerPage(options.perPage ?? 20)
1328
+ perPage: clampPerPage(options.perPage ?? 20)
1318
1329
  },
1319
1330
  "media"
1320
1331
  );
@@ -1356,7 +1367,7 @@ var AniListClient = class {
1356
1367
  status: options.status,
1357
1368
  sort: options.sort,
1358
1369
  page: options.page ?? 1,
1359
- perPage: this.clampPerPage(options.perPage ?? 20)
1370
+ perPage: clampPerPage(options.perPage ?? 20)
1360
1371
  },
1361
1372
  "mediaList"
1362
1373
  );
@@ -1389,7 +1400,7 @@ var AniListClient = class {
1389
1400
  {
1390
1401
  search: options.query,
1391
1402
  page: options.page ?? 1,
1392
- perPage: this.clampPerPage(options.perPage ?? 20)
1403
+ perPage: clampPerPage(options.perPage ?? 20)
1393
1404
  },
1394
1405
  "studios"
1395
1406
  );
@@ -1489,23 +1500,14 @@ var AniListClient = class {
1489
1500
  }
1490
1501
  /** @internal */
1491
1502
  async executeBatch(ids, buildQuery, prefix) {
1492
- const chunks = this.chunk(ids, 50);
1493
- const chunkResults = await Promise.all(
1494
- chunks.map(async (chunk) => {
1495
- const query = buildQuery(chunk);
1496
- const data = await this.request(query);
1497
- return chunk.map((_, i) => data[`${prefix}${i}`]);
1498
- })
1499
- );
1500
- return chunkResults.flat();
1501
- }
1502
- /** @internal */
1503
- chunk(arr, size) {
1504
- const chunks = [];
1505
- for (let i = 0; i < arr.length; i += size) {
1506
- chunks.push(arr.slice(i, i + size));
1503
+ const chunks = chunk(ids, 50);
1504
+ const chunkResults = [];
1505
+ for (const idChunk of chunks) {
1506
+ const query = buildQuery(idChunk);
1507
+ const data = await this.request(query);
1508
+ chunkResults.push(idChunk.map((_, i) => data[`${prefix}${i}`]));
1507
1509
  }
1508
- return chunks;
1510
+ return chunkResults.flat();
1509
1511
  }
1510
1512
  // ── Cache management ──
1511
1513
  /**
@@ -1515,8 +1517,8 @@ var AniListClient = class {
1515
1517
  await this.cacheAdapter.clear();
1516
1518
  }
1517
1519
  /**
1518
- * Number of entries currently in the cache (sync).
1519
- * For async adapters like Redis, this may be approximate.
1520
+ * Number of entries currently in the cache.
1521
+ * For async adapters like Redis, this may return a Promise.
1520
1522
  */
1521
1523
  get cacheSize() {
1522
1524
  return this.cacheAdapter.size;
@@ -1594,15 +1596,14 @@ var RedisCache = class {
1594
1596
  }
1595
1597
  }
1596
1598
  /**
1597
- * Returns -1 because Redis keys can expire silently via TTL.
1598
- * Use `getSize()` for an accurate count.
1599
+ * Get the actual number of keys with this prefix in Redis.
1599
1600
  */
1600
1601
  get size() {
1601
- return -1;
1602
+ return this.getSize();
1602
1603
  }
1603
- /** Get the actual number of keys with this prefix in Redis. */
1604
+ /** @internal */
1604
1605
  async getSize() {
1605
- const keys = await this.client.keys(`${this.prefix}*`);
1606
+ const keys = await this.collectKeys(`${this.prefix}*`);
1606
1607
  return keys.length;
1607
1608
  }
1608
1609
  async keys() {