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/README.md +9 -548
- package/dist/index.d.mts +202 -96
- package/dist/index.d.ts +202 -96
- package/dist/index.js +194 -40
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +192 -41
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -6
package/dist/index.js
CHANGED
|
@@ -35,6 +35,13 @@ var MEDIA_FIELDS_BASE = `
|
|
|
35
35
|
studios { nodes { id name isAnimationStudio siteUrl } }
|
|
36
36
|
isAdult
|
|
37
37
|
siteUrl
|
|
38
|
+
nextAiringEpisode {
|
|
39
|
+
id
|
|
40
|
+
airingAt
|
|
41
|
+
episode
|
|
42
|
+
mediaId
|
|
43
|
+
timeUntilAiring
|
|
44
|
+
}
|
|
38
45
|
`;
|
|
39
46
|
var RELATIONS_FIELDS = `
|
|
40
47
|
relations {
|
|
@@ -202,6 +209,10 @@ query (
|
|
|
202
209
|
$seasonYear: Int,
|
|
203
210
|
$genre: String,
|
|
204
211
|
$tag: String,
|
|
212
|
+
$genre_in: [String],
|
|
213
|
+
$tag_in: [String],
|
|
214
|
+
$genre_not_in: [String],
|
|
215
|
+
$tag_not_in: [String],
|
|
205
216
|
$isAdult: Boolean,
|
|
206
217
|
$sort: [MediaSort],
|
|
207
218
|
$page: Int,
|
|
@@ -218,6 +229,10 @@ query (
|
|
|
218
229
|
seasonYear: $seasonYear,
|
|
219
230
|
genre: $genre,
|
|
220
231
|
tag: $tag,
|
|
232
|
+
genre_in: $genre_in,
|
|
233
|
+
tag_in: $tag_in,
|
|
234
|
+
genre_not_in: $genre_not_in,
|
|
235
|
+
tag_not_in: $tag_not_in,
|
|
221
236
|
isAdult: $isAdult,
|
|
222
237
|
sort: $sort
|
|
223
238
|
) {
|
|
@@ -298,6 +313,15 @@ query ($name: String!) {
|
|
|
298
313
|
${USER_FIELDS}
|
|
299
314
|
}
|
|
300
315
|
}`;
|
|
316
|
+
var QUERY_USER_SEARCH = `
|
|
317
|
+
query ($search: String, $sort: [UserSort], $page: Int, $perPage: Int) {
|
|
318
|
+
Page(page: $page, perPage: $perPage) {
|
|
319
|
+
pageInfo { total perPage currentPage lastPage hasNextPage }
|
|
320
|
+
users(search: $search, sort: $sort) {
|
|
321
|
+
${USER_FIELDS}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}`;
|
|
301
325
|
var QUERY_AIRING_SCHEDULE = `
|
|
302
326
|
query ($airingAt_greater: Int, $airingAt_lesser: Int, $sort: [AiringSort], $page: Int, $perPage: Int) {
|
|
303
327
|
Page(page: $page, perPage: $perPage) {
|
|
@@ -552,6 +576,21 @@ var buildBatchMediaQuery = (ids) => buildBatchQuery(ids, "Media", MEDIA_FIELDS_B
|
|
|
552
576
|
var buildBatchCharacterQuery = (ids) => buildBatchQuery(ids, "Character", CHARACTER_FIELDS, "c");
|
|
553
577
|
var buildBatchStaffQuery = (ids) => buildBatchQuery(ids, "Staff", STAFF_FIELDS, "s");
|
|
554
578
|
|
|
579
|
+
// src/utils/index.ts
|
|
580
|
+
function normalizeQuery(query) {
|
|
581
|
+
return query.replace(/\s+/g, " ").trim();
|
|
582
|
+
}
|
|
583
|
+
function clampPerPage(value) {
|
|
584
|
+
return Math.min(Math.max(value, 1), 50);
|
|
585
|
+
}
|
|
586
|
+
function chunk(arr, size) {
|
|
587
|
+
const chunks = [];
|
|
588
|
+
for (let i = 0; i < arr.length; i += size) {
|
|
589
|
+
chunks.push(arr.slice(i, i + size));
|
|
590
|
+
}
|
|
591
|
+
return chunks;
|
|
592
|
+
}
|
|
593
|
+
|
|
555
594
|
// src/cache/index.ts
|
|
556
595
|
var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
|
|
557
596
|
var MemoryCache = class {
|
|
@@ -563,7 +602,7 @@ var MemoryCache = class {
|
|
|
563
602
|
}
|
|
564
603
|
/** Build a deterministic cache key from a query + variables pair. */
|
|
565
604
|
static key(query, variables) {
|
|
566
|
-
const normalized = query
|
|
605
|
+
const normalized = normalizeQuery(query);
|
|
567
606
|
return `${normalized}|${JSON.stringify(variables, Object.keys(variables).sort())}`;
|
|
568
607
|
}
|
|
569
608
|
/** Retrieve a cached value, or `undefined` if missing / expired. */
|
|
@@ -608,14 +647,17 @@ var MemoryCache = class {
|
|
|
608
647
|
/**
|
|
609
648
|
* Remove all entries whose key matches the given pattern.
|
|
610
649
|
*
|
|
611
|
-
*
|
|
650
|
+
* - **String**: treated as a substring match (e.g. `"Media"` removes all keys containing `"Media"`).
|
|
651
|
+
* - **RegExp**: tested against each key directly.
|
|
652
|
+
*
|
|
653
|
+
* @param pattern — A string (substring match) or RegExp.
|
|
612
654
|
* @returns Number of entries removed.
|
|
613
655
|
*/
|
|
614
656
|
invalidate(pattern) {
|
|
615
|
-
const
|
|
657
|
+
const test = typeof pattern === "string" ? (key) => key.includes(pattern) : (key) => pattern.test(key);
|
|
616
658
|
const toDelete = [];
|
|
617
659
|
for (const key of this.store.keys()) {
|
|
618
|
-
if (
|
|
660
|
+
if (test(key)) toDelete.push(key);
|
|
619
661
|
}
|
|
620
662
|
for (const key of toDelete) this.store.delete(key);
|
|
621
663
|
return toDelete.length;
|
|
@@ -639,8 +681,8 @@ var AniListError = class _AniListError extends Error {
|
|
|
639
681
|
// src/rate-limiter/index.ts
|
|
640
682
|
var RateLimiter = class {
|
|
641
683
|
constructor(options = {}) {
|
|
642
|
-
|
|
643
|
-
this.
|
|
684
|
+
this.head = 0;
|
|
685
|
+
this.count = 0;
|
|
644
686
|
this.maxRequests = options.maxRequests ?? 85;
|
|
645
687
|
this.windowMs = options.windowMs ?? 6e4;
|
|
646
688
|
this.maxRetries = options.maxRetries ?? 3;
|
|
@@ -648,24 +690,34 @@ var RateLimiter = class {
|
|
|
648
690
|
this.enabled = options.enabled ?? true;
|
|
649
691
|
this.timeoutMs = options.timeoutMs ?? 3e4;
|
|
650
692
|
this.retryOnNetworkError = options.retryOnNetworkError ?? true;
|
|
693
|
+
this.timestamps = new Array(this.maxRequests).fill(0);
|
|
651
694
|
}
|
|
652
695
|
/**
|
|
653
696
|
* Wait until it's safe to make a request (respects rate limit window).
|
|
654
697
|
*/
|
|
655
698
|
async acquire() {
|
|
656
699
|
if (!this.enabled) return;
|
|
700
|
+
if (this.count >= this.maxRequests) {
|
|
701
|
+
const oldest = this.timestamps[this.head];
|
|
702
|
+
const now2 = Date.now();
|
|
703
|
+
const elapsed = now2 - oldest;
|
|
704
|
+
if (elapsed < this.windowMs) {
|
|
705
|
+
const waitMs = this.windowMs - elapsed + 50;
|
|
706
|
+
await this.sleep(waitMs);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
657
709
|
const now = Date.now();
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
710
|
+
if (this.count < this.maxRequests) {
|
|
711
|
+
this.timestamps[(this.head + this.count) % this.maxRequests] = now;
|
|
712
|
+
this.count++;
|
|
713
|
+
} else {
|
|
714
|
+
this.timestamps[this.head] = now;
|
|
715
|
+
this.head = (this.head + 1) % this.maxRequests;
|
|
664
716
|
}
|
|
665
|
-
this.timestamps.push(Date.now());
|
|
666
717
|
}
|
|
667
718
|
/**
|
|
668
719
|
* Execute a fetch with automatic retry on 429 responses and network errors.
|
|
720
|
+
* Uses exponential backoff with jitter for retry delays.
|
|
669
721
|
*/
|
|
670
722
|
async fetchWithRetry(url, init, hooks) {
|
|
671
723
|
await this.acquire();
|
|
@@ -678,7 +730,7 @@ var RateLimiter = class {
|
|
|
678
730
|
lastResponse = res;
|
|
679
731
|
if (attempt === this.maxRetries) break;
|
|
680
732
|
const retryAfter = res.headers.get("Retry-After");
|
|
681
|
-
const delayMs = retryAfter ? Number.parseInt(retryAfter, 10) * 1e3 : this.
|
|
733
|
+
const delayMs = retryAfter ? Number.parseInt(retryAfter, 10) * 1e3 : this.exponentialDelay(attempt);
|
|
682
734
|
hooks?.onRateLimit?.(delayMs);
|
|
683
735
|
hooks?.onRetry?.(attempt + 1, "HTTP 429", delayMs);
|
|
684
736
|
await this.sleep(delayMs);
|
|
@@ -686,7 +738,7 @@ var RateLimiter = class {
|
|
|
686
738
|
} catch (err) {
|
|
687
739
|
lastError = err;
|
|
688
740
|
if (this.retryOnNetworkError && isNetworkError(err) && attempt < this.maxRetries) {
|
|
689
|
-
const delayMs = this.
|
|
741
|
+
const delayMs = this.exponentialDelay(attempt);
|
|
690
742
|
hooks?.onRetry?.(attempt + 1, `Network error: ${err.message}`, delayMs);
|
|
691
743
|
await this.sleep(delayMs);
|
|
692
744
|
await this.acquire();
|
|
@@ -698,6 +750,12 @@ var RateLimiter = class {
|
|
|
698
750
|
if (lastResponse) return lastResponse;
|
|
699
751
|
throw lastError;
|
|
700
752
|
}
|
|
753
|
+
/** @internal — Exponential backoff with jitter, capped at 30s */
|
|
754
|
+
exponentialDelay(attempt) {
|
|
755
|
+
const base = this.retryDelayMs * 2 ** attempt;
|
|
756
|
+
const jitter = Math.random() * 1e3;
|
|
757
|
+
return Math.min(base + jitter, 3e4);
|
|
758
|
+
}
|
|
701
759
|
/** @internal */
|
|
702
760
|
async fetchWithTimeout(url, init) {
|
|
703
761
|
if (this.timeoutMs <= 0) return fetch(url, init);
|
|
@@ -737,6 +795,24 @@ var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
|
737
795
|
MediaType2["MANGA"] = "MANGA";
|
|
738
796
|
return MediaType2;
|
|
739
797
|
})(MediaType || {});
|
|
798
|
+
var MediaSource = /* @__PURE__ */ ((MediaSource2) => {
|
|
799
|
+
MediaSource2["ORIGINAL"] = "ORIGINAL";
|
|
800
|
+
MediaSource2["MANGA"] = "MANGA";
|
|
801
|
+
MediaSource2["LIGHT_NOVEL"] = "LIGHT_NOVEL";
|
|
802
|
+
MediaSource2["VISUAL_NOVEL"] = "VISUAL_NOVEL";
|
|
803
|
+
MediaSource2["VIDEO_GAME"] = "VIDEO_GAME";
|
|
804
|
+
MediaSource2["OTHER"] = "OTHER";
|
|
805
|
+
MediaSource2["NOVEL"] = "NOVEL";
|
|
806
|
+
MediaSource2["DOUJINSHI"] = "DOUJINSHI";
|
|
807
|
+
MediaSource2["ANIME"] = "ANIME";
|
|
808
|
+
MediaSource2["WEB_NOVEL"] = "WEB_NOVEL";
|
|
809
|
+
MediaSource2["LIVE_ACTION"] = "LIVE_ACTION";
|
|
810
|
+
MediaSource2["GAME"] = "GAME";
|
|
811
|
+
MediaSource2["COMIC"] = "COMIC";
|
|
812
|
+
MediaSource2["MULTIMEDIA_PROJECT"] = "MULTIMEDIA_PROJECT";
|
|
813
|
+
MediaSource2["PICTURE_BOOK"] = "PICTURE_BOOK";
|
|
814
|
+
return MediaSource2;
|
|
815
|
+
})(MediaSource || {});
|
|
740
816
|
var MediaFormat = /* @__PURE__ */ ((MediaFormat2) => {
|
|
741
817
|
MediaFormat2["TV"] = "TV";
|
|
742
818
|
MediaFormat2["TV_SHORT"] = "TV_SHORT";
|
|
@@ -854,6 +930,35 @@ var CharacterRole = /* @__PURE__ */ ((CharacterRole2) => {
|
|
|
854
930
|
return CharacterRole2;
|
|
855
931
|
})(CharacterRole || {});
|
|
856
932
|
|
|
933
|
+
// src/types/staff.ts
|
|
934
|
+
var StaffSort = /* @__PURE__ */ ((StaffSort2) => {
|
|
935
|
+
StaffSort2["ID"] = "ID";
|
|
936
|
+
StaffSort2["ID_DESC"] = "ID_DESC";
|
|
937
|
+
StaffSort2["ROLE"] = "ROLE";
|
|
938
|
+
StaffSort2["ROLE_DESC"] = "ROLE_DESC";
|
|
939
|
+
StaffSort2["LANGUAGE"] = "LANGUAGE";
|
|
940
|
+
StaffSort2["LANGUAGE_DESC"] = "LANGUAGE_DESC";
|
|
941
|
+
StaffSort2["SEARCH_MATCH"] = "SEARCH_MATCH";
|
|
942
|
+
StaffSort2["FAVOURITES"] = "FAVOURITES";
|
|
943
|
+
StaffSort2["FAVOURITES_DESC"] = "FAVOURITES_DESC";
|
|
944
|
+
StaffSort2["RELEVANCE"] = "RELEVANCE";
|
|
945
|
+
return StaffSort2;
|
|
946
|
+
})(StaffSort || {});
|
|
947
|
+
|
|
948
|
+
// src/types/user.ts
|
|
949
|
+
var UserSort = /* @__PURE__ */ ((UserSort2) => {
|
|
950
|
+
UserSort2["ID"] = "ID";
|
|
951
|
+
UserSort2["ID_DESC"] = "ID_DESC";
|
|
952
|
+
UserSort2["USERNAME"] = "USERNAME";
|
|
953
|
+
UserSort2["USERNAME_DESC"] = "USERNAME_DESC";
|
|
954
|
+
UserSort2["WATCHED_TIME"] = "WATCHED_TIME";
|
|
955
|
+
UserSort2["WATCHED_TIME_DESC"] = "WATCHED_TIME_DESC";
|
|
956
|
+
UserSort2["CHAPTERS_READ"] = "CHAPTERS_READ";
|
|
957
|
+
UserSort2["CHAPTERS_READ_DESC"] = "CHAPTERS_READ_DESC";
|
|
958
|
+
UserSort2["SEARCH_MATCH"] = "SEARCH_MATCH";
|
|
959
|
+
return UserSort2;
|
|
960
|
+
})(UserSort || {});
|
|
961
|
+
|
|
857
962
|
// src/types/lists.ts
|
|
858
963
|
var MediaListStatus = /* @__PURE__ */ ((MediaListStatus2) => {
|
|
859
964
|
MediaListStatus2["CURRENT"] = "CURRENT";
|
|
@@ -898,18 +1003,6 @@ var MediaListSort = /* @__PURE__ */ ((MediaListSort2) => {
|
|
|
898
1003
|
return MediaListSort2;
|
|
899
1004
|
})(MediaListSort || {});
|
|
900
1005
|
|
|
901
|
-
// src/utils/index.ts
|
|
902
|
-
function clampPerPage(value) {
|
|
903
|
-
return Math.min(Math.max(value, 1), 50);
|
|
904
|
-
}
|
|
905
|
-
function chunk(arr, size) {
|
|
906
|
-
const chunks = [];
|
|
907
|
-
for (let i = 0; i < arr.length; i += size) {
|
|
908
|
-
chunks.push(arr.slice(i, i + size));
|
|
909
|
-
}
|
|
910
|
-
return chunks;
|
|
911
|
-
}
|
|
912
|
-
|
|
913
1006
|
// src/client/index.ts
|
|
914
1007
|
var DEFAULT_API_URL = "https://graphql.anilist.co";
|
|
915
1008
|
var AniListClient = class {
|
|
@@ -952,7 +1045,7 @@ var AniListClient = class {
|
|
|
952
1045
|
async executeRequest(query, variables, cacheKey) {
|
|
953
1046
|
const start = Date.now();
|
|
954
1047
|
this.hooks.onRequest?.(query, variables);
|
|
955
|
-
const minifiedQuery = query
|
|
1048
|
+
const minifiedQuery = normalizeQuery(query);
|
|
956
1049
|
const res = await this.rateLimiter.fetchWithRetry(
|
|
957
1050
|
this.apiUrl,
|
|
958
1051
|
{
|
|
@@ -1040,10 +1133,19 @@ var AniListClient = class {
|
|
|
1040
1133
|
* ```
|
|
1041
1134
|
*/
|
|
1042
1135
|
async searchMedia(options = {}) {
|
|
1043
|
-
const { query: search, page = 1, perPage = 20, ...filters } = options;
|
|
1136
|
+
const { query: search, page = 1, perPage = 20, genres, tags, genresExclude, tagsExclude, ...filters } = options;
|
|
1044
1137
|
return this.pagedRequest(
|
|
1045
1138
|
QUERY_MEDIA_SEARCH,
|
|
1046
|
-
{
|
|
1139
|
+
{
|
|
1140
|
+
search,
|
|
1141
|
+
...filters,
|
|
1142
|
+
genre_in: genres,
|
|
1143
|
+
tag_in: tags,
|
|
1144
|
+
genre_not_in: genresExclude,
|
|
1145
|
+
tag_not_in: tagsExclude,
|
|
1146
|
+
page,
|
|
1147
|
+
perPage: clampPerPage(perPage)
|
|
1148
|
+
},
|
|
1047
1149
|
"media"
|
|
1048
1150
|
);
|
|
1049
1151
|
}
|
|
@@ -1057,6 +1159,30 @@ var AniListClient = class {
|
|
|
1057
1159
|
async getTrending(type = "ANIME" /* ANIME */, page = 1, perPage = 20) {
|
|
1058
1160
|
return this.pagedRequest(QUERY_TRENDING, { type, page, perPage: clampPerPage(perPage) }, "media");
|
|
1059
1161
|
}
|
|
1162
|
+
/**
|
|
1163
|
+
* Get the most popular anime or manga.
|
|
1164
|
+
*
|
|
1165
|
+
* Convenience wrapper around `searchMedia` with `sort: POPULARITY_DESC`.
|
|
1166
|
+
*
|
|
1167
|
+
* @param type - `MediaType.ANIME` or `MediaType.MANGA` (defaults to ANIME)
|
|
1168
|
+
* @param page - Page number (default 1)
|
|
1169
|
+
* @param perPage - Results per page (default 20, max 50)
|
|
1170
|
+
*/
|
|
1171
|
+
async getPopular(type = "ANIME" /* ANIME */, page = 1, perPage = 20) {
|
|
1172
|
+
return this.searchMedia({ type, sort: ["POPULARITY_DESC" /* POPULARITY_DESC */], page, perPage });
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* Get the highest-rated anime or manga.
|
|
1176
|
+
*
|
|
1177
|
+
* Convenience wrapper around `searchMedia` with `sort: SCORE_DESC`.
|
|
1178
|
+
*
|
|
1179
|
+
* @param type - `MediaType.ANIME` or `MediaType.MANGA` (defaults to ANIME)
|
|
1180
|
+
* @param page - Page number (default 1)
|
|
1181
|
+
* @param perPage - Results per page (default 20, max 50)
|
|
1182
|
+
*/
|
|
1183
|
+
async getTopRated(type = "ANIME" /* ANIME */, page = 1, perPage = 20) {
|
|
1184
|
+
return this.searchMedia({ type, sort: ["SCORE_DESC" /* SCORE_DESC */], page, perPage });
|
|
1185
|
+
}
|
|
1060
1186
|
/**
|
|
1061
1187
|
* Fetch a character by AniList ID.
|
|
1062
1188
|
*
|
|
@@ -1152,36 +1278,50 @@ var AniListClient = class {
|
|
|
1152
1278
|
);
|
|
1153
1279
|
}
|
|
1154
1280
|
/**
|
|
1155
|
-
* Fetch a user by AniList ID.
|
|
1281
|
+
* Fetch a user by AniList ID or username.
|
|
1156
1282
|
*
|
|
1157
|
-
* @param
|
|
1283
|
+
* @param idOrName - The AniList user ID (number) or username (string)
|
|
1158
1284
|
* @returns The user object
|
|
1159
1285
|
*
|
|
1160
1286
|
* @example
|
|
1161
1287
|
* ```ts
|
|
1162
1288
|
* const user = await client.getUser(1);
|
|
1289
|
+
* const user2 = await client.getUser("AniList");
|
|
1163
1290
|
* console.log(user.name);
|
|
1164
1291
|
* ```
|
|
1165
1292
|
*/
|
|
1166
|
-
async getUser(
|
|
1167
|
-
|
|
1293
|
+
async getUser(idOrName) {
|
|
1294
|
+
if (typeof idOrName === "number") {
|
|
1295
|
+
const data2 = await this.request(QUERY_USER_BY_ID, { id: idOrName });
|
|
1296
|
+
return data2.User;
|
|
1297
|
+
}
|
|
1298
|
+
const data = await this.request(QUERY_USER_BY_NAME, { name: idOrName });
|
|
1168
1299
|
return data.User;
|
|
1169
1300
|
}
|
|
1170
1301
|
/**
|
|
1171
1302
|
* Fetch a user by username.
|
|
1172
1303
|
*
|
|
1304
|
+
* @deprecated Use `getUser(name)` instead.
|
|
1173
1305
|
* @param name - The AniList username
|
|
1174
1306
|
* @returns The user object
|
|
1307
|
+
*/
|
|
1308
|
+
async getUserByName(name) {
|
|
1309
|
+
return this.getUser(name);
|
|
1310
|
+
}
|
|
1311
|
+
/**
|
|
1312
|
+
* Search for users by name.
|
|
1313
|
+
*
|
|
1314
|
+
* @param options - Search / pagination parameters
|
|
1315
|
+
* @returns Paginated results with matching users
|
|
1175
1316
|
*
|
|
1176
1317
|
* @example
|
|
1177
1318
|
* ```ts
|
|
1178
|
-
* const
|
|
1179
|
-
* console.log(user.statistics);
|
|
1319
|
+
* const result = await client.searchUsers({ query: "AniList", perPage: 5 });
|
|
1180
1320
|
* ```
|
|
1181
1321
|
*/
|
|
1182
|
-
async
|
|
1183
|
-
const
|
|
1184
|
-
return
|
|
1322
|
+
async searchUsers(options = {}) {
|
|
1323
|
+
const { query: search, page = 1, perPage = 20, sort } = options;
|
|
1324
|
+
return this.pagedRequest(QUERY_USER_SEARCH, { search, sort, page, perPage: clampPerPage(perPage) }, "users");
|
|
1185
1325
|
}
|
|
1186
1326
|
/**
|
|
1187
1327
|
* Execute an arbitrary GraphQL query against the AniList API.
|
|
@@ -1293,7 +1433,7 @@ var AniListClient = class {
|
|
|
1293
1433
|
mediaId,
|
|
1294
1434
|
sort: options.sort ?? ["RATING_DESC"],
|
|
1295
1435
|
page: options.page ?? 1,
|
|
1296
|
-
perPage: options.perPage ?? 20
|
|
1436
|
+
perPage: clampPerPage(options.perPage ?? 20)
|
|
1297
1437
|
};
|
|
1298
1438
|
const data = await this.request(QUERY_RECOMMENDATIONS, variables);
|
|
1299
1439
|
return {
|
|
@@ -1546,6 +1686,17 @@ var AniListClient = class {
|
|
|
1546
1686
|
}
|
|
1547
1687
|
return count;
|
|
1548
1688
|
}
|
|
1689
|
+
/**
|
|
1690
|
+
* Clean up resources held by the client.
|
|
1691
|
+
*
|
|
1692
|
+
* Clears the in-memory cache and aborts any pending in-flight requests.
|
|
1693
|
+
* If using a custom cache adapter (e.g. Redis), call its close/disconnect
|
|
1694
|
+
* method separately.
|
|
1695
|
+
*/
|
|
1696
|
+
async destroy() {
|
|
1697
|
+
await this.cacheAdapter.clear();
|
|
1698
|
+
this.inFlight.clear();
|
|
1699
|
+
}
|
|
1549
1700
|
};
|
|
1550
1701
|
|
|
1551
1702
|
// src/cache/redis.ts
|
|
@@ -1642,11 +1793,14 @@ exports.MediaListStatus = MediaListStatus;
|
|
|
1642
1793
|
exports.MediaRelationType = MediaRelationType;
|
|
1643
1794
|
exports.MediaSeason = MediaSeason;
|
|
1644
1795
|
exports.MediaSort = MediaSort;
|
|
1796
|
+
exports.MediaSource = MediaSource;
|
|
1645
1797
|
exports.MediaStatus = MediaStatus;
|
|
1646
1798
|
exports.MediaType = MediaType;
|
|
1647
1799
|
exports.MemoryCache = MemoryCache;
|
|
1648
1800
|
exports.RateLimiter = RateLimiter;
|
|
1649
1801
|
exports.RecommendationSort = RecommendationSort;
|
|
1650
1802
|
exports.RedisCache = RedisCache;
|
|
1803
|
+
exports.StaffSort = StaffSort;
|
|
1804
|
+
exports.UserSort = UserSort;
|
|
1651
1805
|
//# sourceMappingURL=index.js.map
|
|
1652
1806
|
//# sourceMappingURL=index.js.map
|