ani-client 1.4.1 → 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/README.md +14 -2
- package/dist/index.d.mts +411 -358
- package/dist/index.d.ts +411 -358
- package/dist/index.js +118 -59
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +118 -59
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -129,6 +129,46 @@ var STAFF_FIELDS = `
|
|
|
129
129
|
favourites
|
|
130
130
|
siteUrl
|
|
131
131
|
`;
|
|
132
|
+
var STAFF_MEDIA_FIELDS = `
|
|
133
|
+
staffMedia(perPage: $perPage, sort: [POPULARITY_DESC]) {
|
|
134
|
+
nodes {
|
|
135
|
+
id
|
|
136
|
+
title { romaji english native userPreferred }
|
|
137
|
+
type
|
|
138
|
+
format
|
|
139
|
+
status
|
|
140
|
+
coverImage { extraLarge large medium color }
|
|
141
|
+
bannerImage
|
|
142
|
+
genres
|
|
143
|
+
averageScore
|
|
144
|
+
meanScore
|
|
145
|
+
popularity
|
|
146
|
+
favourites
|
|
147
|
+
episodes
|
|
148
|
+
trending
|
|
149
|
+
hashtag
|
|
150
|
+
season
|
|
151
|
+
seasonYear
|
|
152
|
+
startDate { year month day }
|
|
153
|
+
endDate { year month day }
|
|
154
|
+
nextAiringEpisode {
|
|
155
|
+
id
|
|
156
|
+
airingAt
|
|
157
|
+
episode
|
|
158
|
+
mediaId
|
|
159
|
+
timeUntilAiring
|
|
160
|
+
}
|
|
161
|
+
studios {
|
|
162
|
+
edges {
|
|
163
|
+
node {
|
|
164
|
+
name
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
siteUrl
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
`;
|
|
132
172
|
var USER_FIELDS = `
|
|
133
173
|
id
|
|
134
174
|
name
|
|
@@ -230,6 +270,13 @@ query ($id: Int!) {
|
|
|
230
270
|
${STAFF_FIELDS}
|
|
231
271
|
}
|
|
232
272
|
}`;
|
|
273
|
+
var QUERY_STAFF_BY_ID_WITH_MEDIA = `
|
|
274
|
+
query ($id: Int!, $perPage: Int) {
|
|
275
|
+
Staff(id: $id) {
|
|
276
|
+
${STAFF_FIELDS}
|
|
277
|
+
${STAFF_MEDIA_FIELDS}
|
|
278
|
+
}
|
|
279
|
+
}`;
|
|
233
280
|
var QUERY_STAFF_SEARCH = `
|
|
234
281
|
query ($search: String, $sort: [StaffSort], $page: Int, $perPage: Int) {
|
|
235
282
|
Page(page: $page, perPage: $perPage) {
|
|
@@ -582,6 +629,7 @@ var AniListError = class _AniListError extends Error {
|
|
|
582
629
|
this.name = "AniListError";
|
|
583
630
|
this.status = status;
|
|
584
631
|
this.errors = errors;
|
|
632
|
+
Object.setPrototypeOf(this, _AniListError.prototype);
|
|
585
633
|
if (Error.captureStackTrace) {
|
|
586
634
|
Error.captureStackTrace(this, _AniListError);
|
|
587
635
|
}
|
|
@@ -683,7 +731,7 @@ function isNetworkError(err) {
|
|
|
683
731
|
return false;
|
|
684
732
|
}
|
|
685
733
|
|
|
686
|
-
// src/types/
|
|
734
|
+
// src/types/media.ts
|
|
687
735
|
var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
688
736
|
MediaType2["ANIME"] = "ANIME";
|
|
689
737
|
MediaType2["MANGA"] = "MANGA";
|
|
@@ -764,22 +812,6 @@ var AiringSort = /* @__PURE__ */ ((AiringSort2) => {
|
|
|
764
812
|
AiringSort2["EPISODE_DESC"] = "EPISODE_DESC";
|
|
765
813
|
return AiringSort2;
|
|
766
814
|
})(AiringSort || {});
|
|
767
|
-
var CharacterSort = /* @__PURE__ */ ((CharacterSort2) => {
|
|
768
|
-
CharacterSort2["ID"] = "ID";
|
|
769
|
-
CharacterSort2["ID_DESC"] = "ID_DESC";
|
|
770
|
-
CharacterSort2["ROLE"] = "ROLE";
|
|
771
|
-
CharacterSort2["ROLE_DESC"] = "ROLE_DESC";
|
|
772
|
-
CharacterSort2["SEARCH_MATCH"] = "SEARCH_MATCH";
|
|
773
|
-
CharacterSort2["FAVOURITES"] = "FAVOURITES";
|
|
774
|
-
CharacterSort2["FAVOURITES_DESC"] = "FAVOURITES_DESC";
|
|
775
|
-
return CharacterSort2;
|
|
776
|
-
})(CharacterSort || {});
|
|
777
|
-
var CharacterRole = /* @__PURE__ */ ((CharacterRole2) => {
|
|
778
|
-
CharacterRole2["MAIN"] = "MAIN";
|
|
779
|
-
CharacterRole2["SUPPORTING"] = "SUPPORTING";
|
|
780
|
-
CharacterRole2["BACKGROUND"] = "BACKGROUND";
|
|
781
|
-
return CharacterRole2;
|
|
782
|
-
})(CharacterRole || {});
|
|
783
815
|
var MediaRelationType = /* @__PURE__ */ ((MediaRelationType2) => {
|
|
784
816
|
MediaRelationType2["ADAPTATION"] = "ADAPTATION";
|
|
785
817
|
MediaRelationType2["PREQUEL"] = "PREQUEL";
|
|
@@ -803,6 +835,26 @@ var RecommendationSort = /* @__PURE__ */ ((RecommendationSort2) => {
|
|
|
803
835
|
RecommendationSort2["RATING_DESC"] = "RATING_DESC";
|
|
804
836
|
return RecommendationSort2;
|
|
805
837
|
})(RecommendationSort || {});
|
|
838
|
+
|
|
839
|
+
// src/types/character.ts
|
|
840
|
+
var CharacterSort = /* @__PURE__ */ ((CharacterSort2) => {
|
|
841
|
+
CharacterSort2["ID"] = "ID";
|
|
842
|
+
CharacterSort2["ID_DESC"] = "ID_DESC";
|
|
843
|
+
CharacterSort2["ROLE"] = "ROLE";
|
|
844
|
+
CharacterSort2["ROLE_DESC"] = "ROLE_DESC";
|
|
845
|
+
CharacterSort2["SEARCH_MATCH"] = "SEARCH_MATCH";
|
|
846
|
+
CharacterSort2["FAVOURITES"] = "FAVOURITES";
|
|
847
|
+
CharacterSort2["FAVOURITES_DESC"] = "FAVOURITES_DESC";
|
|
848
|
+
return CharacterSort2;
|
|
849
|
+
})(CharacterSort || {});
|
|
850
|
+
var CharacterRole = /* @__PURE__ */ ((CharacterRole2) => {
|
|
851
|
+
CharacterRole2["MAIN"] = "MAIN";
|
|
852
|
+
CharacterRole2["SUPPORTING"] = "SUPPORTING";
|
|
853
|
+
CharacterRole2["BACKGROUND"] = "BACKGROUND";
|
|
854
|
+
return CharacterRole2;
|
|
855
|
+
})(CharacterRole || {});
|
|
856
|
+
|
|
857
|
+
// src/types/lists.ts
|
|
806
858
|
var MediaListStatus = /* @__PURE__ */ ((MediaListStatus2) => {
|
|
807
859
|
MediaListStatus2["CURRENT"] = "CURRENT";
|
|
808
860
|
MediaListStatus2["PLANNING"] = "PLANNING";
|
|
@@ -846,6 +898,18 @@ var MediaListSort = /* @__PURE__ */ ((MediaListSort2) => {
|
|
|
846
898
|
return MediaListSort2;
|
|
847
899
|
})(MediaListSort || {});
|
|
848
900
|
|
|
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
|
+
|
|
849
913
|
// src/client/index.ts
|
|
850
914
|
var DEFAULT_API_URL = "https://graphql.anilist.co";
|
|
851
915
|
var AniListClient = class {
|
|
@@ -888,12 +952,13 @@ var AniListClient = class {
|
|
|
888
952
|
async executeRequest(query, variables, cacheKey) {
|
|
889
953
|
const start = Date.now();
|
|
890
954
|
this.hooks.onRequest?.(query, variables);
|
|
955
|
+
const minifiedQuery = query.replace(/\s+/g, " ").trim();
|
|
891
956
|
const res = await this.rateLimiter.fetchWithRetry(
|
|
892
957
|
this.apiUrl,
|
|
893
958
|
{
|
|
894
959
|
method: "POST",
|
|
895
960
|
headers: this.headers,
|
|
896
|
-
body: JSON.stringify({ query, variables })
|
|
961
|
+
body: JSON.stringify({ query: minifiedQuery, variables })
|
|
897
962
|
},
|
|
898
963
|
{ onRetry: this.hooks.onRetry, onRateLimit: this.hooks.onRateLimit }
|
|
899
964
|
);
|
|
@@ -919,13 +984,6 @@ var AniListClient = class {
|
|
|
919
984
|
}
|
|
920
985
|
return { pageInfo: data.Page.pageInfo, results };
|
|
921
986
|
}
|
|
922
|
-
/**
|
|
923
|
-
* @internal
|
|
924
|
-
* Clamp perPage to AniList's maximum of 50.
|
|
925
|
-
*/
|
|
926
|
-
clampPerPage(value) {
|
|
927
|
-
return Math.min(Math.max(value, 1), 50);
|
|
928
|
-
}
|
|
929
987
|
/**
|
|
930
988
|
* Fetch a single media entry by its AniList ID.
|
|
931
989
|
*
|
|
@@ -985,7 +1043,7 @@ var AniListClient = class {
|
|
|
985
1043
|
const { query: search, page = 1, perPage = 20, ...filters } = options;
|
|
986
1044
|
return this.pagedRequest(
|
|
987
1045
|
QUERY_MEDIA_SEARCH,
|
|
988
|
-
{ search, ...filters, page, perPage:
|
|
1046
|
+
{ search, ...filters, page, perPage: clampPerPage(perPage) },
|
|
989
1047
|
"media"
|
|
990
1048
|
);
|
|
991
1049
|
}
|
|
@@ -997,7 +1055,7 @@ var AniListClient = class {
|
|
|
997
1055
|
* @param perPage - Results per page (default 20, max 50)
|
|
998
1056
|
*/
|
|
999
1057
|
async getTrending(type = "ANIME" /* ANIME */, page = 1, perPage = 20) {
|
|
1000
|
-
return this.pagedRequest(QUERY_TRENDING, { type, page, perPage:
|
|
1058
|
+
return this.pagedRequest(QUERY_TRENDING, { type, page, perPage: clampPerPage(perPage) }, "media");
|
|
1001
1059
|
}
|
|
1002
1060
|
/**
|
|
1003
1061
|
* Fetch a character by AniList ID.
|
|
@@ -1043,7 +1101,7 @@ var AniListClient = class {
|
|
|
1043
1101
|
const gqlQuery = voiceActors ? QUERY_CHARACTER_SEARCH_WITH_VA : QUERY_CHARACTER_SEARCH;
|
|
1044
1102
|
return this.pagedRequest(
|
|
1045
1103
|
gqlQuery,
|
|
1046
|
-
{ search, ...rest, page, perPage:
|
|
1104
|
+
{ search, ...rest, page, perPage: clampPerPage(perPage) },
|
|
1047
1105
|
"characters"
|
|
1048
1106
|
);
|
|
1049
1107
|
}
|
|
@@ -1051,15 +1109,26 @@ var AniListClient = class {
|
|
|
1051
1109
|
* Fetch a staff member by AniList ID.
|
|
1052
1110
|
*
|
|
1053
1111
|
* @param id - The AniList staff ID
|
|
1112
|
+
* @param include - Optional include options to fetch related data (e.g. media)
|
|
1054
1113
|
* @returns The staff object
|
|
1055
1114
|
*
|
|
1056
1115
|
* @example
|
|
1057
1116
|
* ```ts
|
|
1058
1117
|
* const staff = await client.getStaff(95001);
|
|
1059
1118
|
* console.log(staff.name.full);
|
|
1119
|
+
*
|
|
1120
|
+
* // With media the staff worked on
|
|
1121
|
+
* const staff = await client.getStaff(95001, { media: true });
|
|
1122
|
+
* staff.staffMedia?.nodes.forEach((m) => console.log(m.title.romaji));
|
|
1060
1123
|
* ```
|
|
1061
1124
|
*/
|
|
1062
|
-
async getStaff(id) {
|
|
1125
|
+
async getStaff(id, include) {
|
|
1126
|
+
if (include?.media) {
|
|
1127
|
+
const opts = typeof include.media === "object" ? include.media : {};
|
|
1128
|
+
const perPage = opts.perPage ?? 25;
|
|
1129
|
+
const data2 = await this.request(QUERY_STAFF_BY_ID_WITH_MEDIA, { id, perPage });
|
|
1130
|
+
return data2.Staff;
|
|
1131
|
+
}
|
|
1063
1132
|
const data = await this.request(QUERY_STAFF_BY_ID, { id });
|
|
1064
1133
|
return data.Staff;
|
|
1065
1134
|
}
|
|
@@ -1078,7 +1147,7 @@ var AniListClient = class {
|
|
|
1078
1147
|
const { query: search, page = 1, perPage = 20, sort } = options;
|
|
1079
1148
|
return this.pagedRequest(
|
|
1080
1149
|
QUERY_STAFF_SEARCH,
|
|
1081
|
-
{ search, sort, page, perPage:
|
|
1150
|
+
{ search, sort, page, perPage: clampPerPage(perPage) },
|
|
1082
1151
|
"staff"
|
|
1083
1152
|
);
|
|
1084
1153
|
}
|
|
@@ -1147,7 +1216,7 @@ var AniListClient = class {
|
|
|
1147
1216
|
airingAt_lesser: options.airingAtLesser ?? now,
|
|
1148
1217
|
sort: options.sort ?? ["TIME_DESC"],
|
|
1149
1218
|
page: options.page ?? 1,
|
|
1150
|
-
perPage:
|
|
1219
|
+
perPage: clampPerPage(options.perPage ?? 20)
|
|
1151
1220
|
};
|
|
1152
1221
|
return this.pagedRequest(QUERY_AIRING_SCHEDULE, variables, "airingSchedules");
|
|
1153
1222
|
}
|
|
@@ -1170,7 +1239,7 @@ var AniListClient = class {
|
|
|
1170
1239
|
QUERY_RECENT_CHAPTERS,
|
|
1171
1240
|
{
|
|
1172
1241
|
page: options.page ?? 1,
|
|
1173
|
-
perPage:
|
|
1242
|
+
perPage: clampPerPage(options.perPage ?? 20)
|
|
1174
1243
|
},
|
|
1175
1244
|
"media"
|
|
1176
1245
|
);
|
|
@@ -1196,7 +1265,7 @@ var AniListClient = class {
|
|
|
1196
1265
|
type: options.type,
|
|
1197
1266
|
sort: options.sort ?? ["POPULARITY_DESC"],
|
|
1198
1267
|
page: options.page ?? 1,
|
|
1199
|
-
perPage:
|
|
1268
|
+
perPage: clampPerPage(options.perPage ?? 20)
|
|
1200
1269
|
},
|
|
1201
1270
|
"media"
|
|
1202
1271
|
);
|
|
@@ -1258,7 +1327,7 @@ var AniListClient = class {
|
|
|
1258
1327
|
type: options.type ?? "ANIME",
|
|
1259
1328
|
sort: options.sort ?? ["POPULARITY_DESC"],
|
|
1260
1329
|
page: options.page ?? 1,
|
|
1261
|
-
perPage:
|
|
1330
|
+
perPage: clampPerPage(options.perPage ?? 20)
|
|
1262
1331
|
},
|
|
1263
1332
|
"media"
|
|
1264
1333
|
);
|
|
@@ -1300,7 +1369,7 @@ var AniListClient = class {
|
|
|
1300
1369
|
status: options.status,
|
|
1301
1370
|
sort: options.sort,
|
|
1302
1371
|
page: options.page ?? 1,
|
|
1303
|
-
perPage:
|
|
1372
|
+
perPage: clampPerPage(options.perPage ?? 20)
|
|
1304
1373
|
},
|
|
1305
1374
|
"mediaList"
|
|
1306
1375
|
);
|
|
@@ -1333,7 +1402,7 @@ var AniListClient = class {
|
|
|
1333
1402
|
{
|
|
1334
1403
|
search: options.query,
|
|
1335
1404
|
page: options.page ?? 1,
|
|
1336
|
-
perPage:
|
|
1405
|
+
perPage: clampPerPage(options.perPage ?? 20)
|
|
1337
1406
|
},
|
|
1338
1407
|
"studios"
|
|
1339
1408
|
);
|
|
@@ -1433,23 +1502,14 @@ var AniListClient = class {
|
|
|
1433
1502
|
}
|
|
1434
1503
|
/** @internal */
|
|
1435
1504
|
async executeBatch(ids, buildQuery, prefix) {
|
|
1436
|
-
const chunks =
|
|
1437
|
-
const chunkResults =
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
})
|
|
1443
|
-
);
|
|
1444
|
-
return chunkResults.flat();
|
|
1445
|
-
}
|
|
1446
|
-
/** @internal */
|
|
1447
|
-
chunk(arr, size) {
|
|
1448
|
-
const chunks = [];
|
|
1449
|
-
for (let i = 0; i < arr.length; i += size) {
|
|
1450
|
-
chunks.push(arr.slice(i, i + size));
|
|
1505
|
+
const chunks = chunk(ids, 50);
|
|
1506
|
+
const chunkResults = [];
|
|
1507
|
+
for (const idChunk of chunks) {
|
|
1508
|
+
const query = buildQuery(idChunk);
|
|
1509
|
+
const data = await this.request(query);
|
|
1510
|
+
chunkResults.push(idChunk.map((_, i) => data[`${prefix}${i}`]));
|
|
1451
1511
|
}
|
|
1452
|
-
return
|
|
1512
|
+
return chunkResults.flat();
|
|
1453
1513
|
}
|
|
1454
1514
|
// ── Cache management ──
|
|
1455
1515
|
/**
|
|
@@ -1459,8 +1519,8 @@ var AniListClient = class {
|
|
|
1459
1519
|
await this.cacheAdapter.clear();
|
|
1460
1520
|
}
|
|
1461
1521
|
/**
|
|
1462
|
-
* Number of entries currently in the cache
|
|
1463
|
-
* For async adapters like Redis, this may
|
|
1522
|
+
* Number of entries currently in the cache.
|
|
1523
|
+
* For async adapters like Redis, this may return a Promise.
|
|
1464
1524
|
*/
|
|
1465
1525
|
get cacheSize() {
|
|
1466
1526
|
return this.cacheAdapter.size;
|
|
@@ -1538,15 +1598,14 @@ var RedisCache = class {
|
|
|
1538
1598
|
}
|
|
1539
1599
|
}
|
|
1540
1600
|
/**
|
|
1541
|
-
*
|
|
1542
|
-
* Use `getSize()` for an accurate count.
|
|
1601
|
+
* Get the actual number of keys with this prefix in Redis.
|
|
1543
1602
|
*/
|
|
1544
1603
|
get size() {
|
|
1545
|
-
return
|
|
1604
|
+
return this.getSize();
|
|
1546
1605
|
}
|
|
1547
|
-
/**
|
|
1606
|
+
/** @internal */
|
|
1548
1607
|
async getSize() {
|
|
1549
|
-
const keys = await this.
|
|
1608
|
+
const keys = await this.collectKeys(`${this.prefix}*`);
|
|
1550
1609
|
return keys.length;
|
|
1551
1610
|
}
|
|
1552
1611
|
async keys() {
|