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.mjs
CHANGED
|
@@ -127,6 +127,46 @@ var STAFF_FIELDS = `
|
|
|
127
127
|
favourites
|
|
128
128
|
siteUrl
|
|
129
129
|
`;
|
|
130
|
+
var STAFF_MEDIA_FIELDS = `
|
|
131
|
+
staffMedia(perPage: $perPage, sort: [POPULARITY_DESC]) {
|
|
132
|
+
nodes {
|
|
133
|
+
id
|
|
134
|
+
title { romaji english native userPreferred }
|
|
135
|
+
type
|
|
136
|
+
format
|
|
137
|
+
status
|
|
138
|
+
coverImage { extraLarge large medium color }
|
|
139
|
+
bannerImage
|
|
140
|
+
genres
|
|
141
|
+
averageScore
|
|
142
|
+
meanScore
|
|
143
|
+
popularity
|
|
144
|
+
favourites
|
|
145
|
+
episodes
|
|
146
|
+
trending
|
|
147
|
+
hashtag
|
|
148
|
+
season
|
|
149
|
+
seasonYear
|
|
150
|
+
startDate { year month day }
|
|
151
|
+
endDate { year month day }
|
|
152
|
+
nextAiringEpisode {
|
|
153
|
+
id
|
|
154
|
+
airingAt
|
|
155
|
+
episode
|
|
156
|
+
mediaId
|
|
157
|
+
timeUntilAiring
|
|
158
|
+
}
|
|
159
|
+
studios {
|
|
160
|
+
edges {
|
|
161
|
+
node {
|
|
162
|
+
name
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
siteUrl
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
`;
|
|
130
170
|
var USER_FIELDS = `
|
|
131
171
|
id
|
|
132
172
|
name
|
|
@@ -228,6 +268,13 @@ query ($id: Int!) {
|
|
|
228
268
|
${STAFF_FIELDS}
|
|
229
269
|
}
|
|
230
270
|
}`;
|
|
271
|
+
var QUERY_STAFF_BY_ID_WITH_MEDIA = `
|
|
272
|
+
query ($id: Int!, $perPage: Int) {
|
|
273
|
+
Staff(id: $id) {
|
|
274
|
+
${STAFF_FIELDS}
|
|
275
|
+
${STAFF_MEDIA_FIELDS}
|
|
276
|
+
}
|
|
277
|
+
}`;
|
|
231
278
|
var QUERY_STAFF_SEARCH = `
|
|
232
279
|
query ($search: String, $sort: [StaffSort], $page: Int, $perPage: Int) {
|
|
233
280
|
Page(page: $page, perPage: $perPage) {
|
|
@@ -580,6 +627,7 @@ var AniListError = class _AniListError extends Error {
|
|
|
580
627
|
this.name = "AniListError";
|
|
581
628
|
this.status = status;
|
|
582
629
|
this.errors = errors;
|
|
630
|
+
Object.setPrototypeOf(this, _AniListError.prototype);
|
|
583
631
|
if (Error.captureStackTrace) {
|
|
584
632
|
Error.captureStackTrace(this, _AniListError);
|
|
585
633
|
}
|
|
@@ -681,7 +729,7 @@ function isNetworkError(err) {
|
|
|
681
729
|
return false;
|
|
682
730
|
}
|
|
683
731
|
|
|
684
|
-
// src/types/
|
|
732
|
+
// src/types/media.ts
|
|
685
733
|
var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
686
734
|
MediaType2["ANIME"] = "ANIME";
|
|
687
735
|
MediaType2["MANGA"] = "MANGA";
|
|
@@ -762,22 +810,6 @@ var AiringSort = /* @__PURE__ */ ((AiringSort2) => {
|
|
|
762
810
|
AiringSort2["EPISODE_DESC"] = "EPISODE_DESC";
|
|
763
811
|
return AiringSort2;
|
|
764
812
|
})(AiringSort || {});
|
|
765
|
-
var CharacterSort = /* @__PURE__ */ ((CharacterSort2) => {
|
|
766
|
-
CharacterSort2["ID"] = "ID";
|
|
767
|
-
CharacterSort2["ID_DESC"] = "ID_DESC";
|
|
768
|
-
CharacterSort2["ROLE"] = "ROLE";
|
|
769
|
-
CharacterSort2["ROLE_DESC"] = "ROLE_DESC";
|
|
770
|
-
CharacterSort2["SEARCH_MATCH"] = "SEARCH_MATCH";
|
|
771
|
-
CharacterSort2["FAVOURITES"] = "FAVOURITES";
|
|
772
|
-
CharacterSort2["FAVOURITES_DESC"] = "FAVOURITES_DESC";
|
|
773
|
-
return CharacterSort2;
|
|
774
|
-
})(CharacterSort || {});
|
|
775
|
-
var CharacterRole = /* @__PURE__ */ ((CharacterRole2) => {
|
|
776
|
-
CharacterRole2["MAIN"] = "MAIN";
|
|
777
|
-
CharacterRole2["SUPPORTING"] = "SUPPORTING";
|
|
778
|
-
CharacterRole2["BACKGROUND"] = "BACKGROUND";
|
|
779
|
-
return CharacterRole2;
|
|
780
|
-
})(CharacterRole || {});
|
|
781
813
|
var MediaRelationType = /* @__PURE__ */ ((MediaRelationType2) => {
|
|
782
814
|
MediaRelationType2["ADAPTATION"] = "ADAPTATION";
|
|
783
815
|
MediaRelationType2["PREQUEL"] = "PREQUEL";
|
|
@@ -801,6 +833,26 @@ var RecommendationSort = /* @__PURE__ */ ((RecommendationSort2) => {
|
|
|
801
833
|
RecommendationSort2["RATING_DESC"] = "RATING_DESC";
|
|
802
834
|
return RecommendationSort2;
|
|
803
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
|
|
804
856
|
var MediaListStatus = /* @__PURE__ */ ((MediaListStatus2) => {
|
|
805
857
|
MediaListStatus2["CURRENT"] = "CURRENT";
|
|
806
858
|
MediaListStatus2["PLANNING"] = "PLANNING";
|
|
@@ -844,6 +896,18 @@ var MediaListSort = /* @__PURE__ */ ((MediaListSort2) => {
|
|
|
844
896
|
return MediaListSort2;
|
|
845
897
|
})(MediaListSort || {});
|
|
846
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
|
+
|
|
847
911
|
// src/client/index.ts
|
|
848
912
|
var DEFAULT_API_URL = "https://graphql.anilist.co";
|
|
849
913
|
var AniListClient = class {
|
|
@@ -886,12 +950,13 @@ var AniListClient = class {
|
|
|
886
950
|
async executeRequest(query, variables, cacheKey) {
|
|
887
951
|
const start = Date.now();
|
|
888
952
|
this.hooks.onRequest?.(query, variables);
|
|
953
|
+
const minifiedQuery = query.replace(/\s+/g, " ").trim();
|
|
889
954
|
const res = await this.rateLimiter.fetchWithRetry(
|
|
890
955
|
this.apiUrl,
|
|
891
956
|
{
|
|
892
957
|
method: "POST",
|
|
893
958
|
headers: this.headers,
|
|
894
|
-
body: JSON.stringify({ query, variables })
|
|
959
|
+
body: JSON.stringify({ query: minifiedQuery, variables })
|
|
895
960
|
},
|
|
896
961
|
{ onRetry: this.hooks.onRetry, onRateLimit: this.hooks.onRateLimit }
|
|
897
962
|
);
|
|
@@ -917,13 +982,6 @@ var AniListClient = class {
|
|
|
917
982
|
}
|
|
918
983
|
return { pageInfo: data.Page.pageInfo, results };
|
|
919
984
|
}
|
|
920
|
-
/**
|
|
921
|
-
* @internal
|
|
922
|
-
* Clamp perPage to AniList's maximum of 50.
|
|
923
|
-
*/
|
|
924
|
-
clampPerPage(value) {
|
|
925
|
-
return Math.min(Math.max(value, 1), 50);
|
|
926
|
-
}
|
|
927
985
|
/**
|
|
928
986
|
* Fetch a single media entry by its AniList ID.
|
|
929
987
|
*
|
|
@@ -983,7 +1041,7 @@ var AniListClient = class {
|
|
|
983
1041
|
const { query: search, page = 1, perPage = 20, ...filters } = options;
|
|
984
1042
|
return this.pagedRequest(
|
|
985
1043
|
QUERY_MEDIA_SEARCH,
|
|
986
|
-
{ search, ...filters, page, perPage:
|
|
1044
|
+
{ search, ...filters, page, perPage: clampPerPage(perPage) },
|
|
987
1045
|
"media"
|
|
988
1046
|
);
|
|
989
1047
|
}
|
|
@@ -995,7 +1053,7 @@ var AniListClient = class {
|
|
|
995
1053
|
* @param perPage - Results per page (default 20, max 50)
|
|
996
1054
|
*/
|
|
997
1055
|
async getTrending(type = "ANIME" /* ANIME */, page = 1, perPage = 20) {
|
|
998
|
-
return this.pagedRequest(QUERY_TRENDING, { type, page, perPage:
|
|
1056
|
+
return this.pagedRequest(QUERY_TRENDING, { type, page, perPage: clampPerPage(perPage) }, "media");
|
|
999
1057
|
}
|
|
1000
1058
|
/**
|
|
1001
1059
|
* Fetch a character by AniList ID.
|
|
@@ -1041,7 +1099,7 @@ var AniListClient = class {
|
|
|
1041
1099
|
const gqlQuery = voiceActors ? QUERY_CHARACTER_SEARCH_WITH_VA : QUERY_CHARACTER_SEARCH;
|
|
1042
1100
|
return this.pagedRequest(
|
|
1043
1101
|
gqlQuery,
|
|
1044
|
-
{ search, ...rest, page, perPage:
|
|
1102
|
+
{ search, ...rest, page, perPage: clampPerPage(perPage) },
|
|
1045
1103
|
"characters"
|
|
1046
1104
|
);
|
|
1047
1105
|
}
|
|
@@ -1049,15 +1107,26 @@ var AniListClient = class {
|
|
|
1049
1107
|
* Fetch a staff member by AniList ID.
|
|
1050
1108
|
*
|
|
1051
1109
|
* @param id - The AniList staff ID
|
|
1110
|
+
* @param include - Optional include options to fetch related data (e.g. media)
|
|
1052
1111
|
* @returns The staff object
|
|
1053
1112
|
*
|
|
1054
1113
|
* @example
|
|
1055
1114
|
* ```ts
|
|
1056
1115
|
* const staff = await client.getStaff(95001);
|
|
1057
1116
|
* console.log(staff.name.full);
|
|
1117
|
+
*
|
|
1118
|
+
* // With media the staff worked on
|
|
1119
|
+
* const staff = await client.getStaff(95001, { media: true });
|
|
1120
|
+
* staff.staffMedia?.nodes.forEach((m) => console.log(m.title.romaji));
|
|
1058
1121
|
* ```
|
|
1059
1122
|
*/
|
|
1060
|
-
async getStaff(id) {
|
|
1123
|
+
async getStaff(id, include) {
|
|
1124
|
+
if (include?.media) {
|
|
1125
|
+
const opts = typeof include.media === "object" ? include.media : {};
|
|
1126
|
+
const perPage = opts.perPage ?? 25;
|
|
1127
|
+
const data2 = await this.request(QUERY_STAFF_BY_ID_WITH_MEDIA, { id, perPage });
|
|
1128
|
+
return data2.Staff;
|
|
1129
|
+
}
|
|
1061
1130
|
const data = await this.request(QUERY_STAFF_BY_ID, { id });
|
|
1062
1131
|
return data.Staff;
|
|
1063
1132
|
}
|
|
@@ -1076,7 +1145,7 @@ var AniListClient = class {
|
|
|
1076
1145
|
const { query: search, page = 1, perPage = 20, sort } = options;
|
|
1077
1146
|
return this.pagedRequest(
|
|
1078
1147
|
QUERY_STAFF_SEARCH,
|
|
1079
|
-
{ search, sort, page, perPage:
|
|
1148
|
+
{ search, sort, page, perPage: clampPerPage(perPage) },
|
|
1080
1149
|
"staff"
|
|
1081
1150
|
);
|
|
1082
1151
|
}
|
|
@@ -1145,7 +1214,7 @@ var AniListClient = class {
|
|
|
1145
1214
|
airingAt_lesser: options.airingAtLesser ?? now,
|
|
1146
1215
|
sort: options.sort ?? ["TIME_DESC"],
|
|
1147
1216
|
page: options.page ?? 1,
|
|
1148
|
-
perPage:
|
|
1217
|
+
perPage: clampPerPage(options.perPage ?? 20)
|
|
1149
1218
|
};
|
|
1150
1219
|
return this.pagedRequest(QUERY_AIRING_SCHEDULE, variables, "airingSchedules");
|
|
1151
1220
|
}
|
|
@@ -1168,7 +1237,7 @@ var AniListClient = class {
|
|
|
1168
1237
|
QUERY_RECENT_CHAPTERS,
|
|
1169
1238
|
{
|
|
1170
1239
|
page: options.page ?? 1,
|
|
1171
|
-
perPage:
|
|
1240
|
+
perPage: clampPerPage(options.perPage ?? 20)
|
|
1172
1241
|
},
|
|
1173
1242
|
"media"
|
|
1174
1243
|
);
|
|
@@ -1194,7 +1263,7 @@ var AniListClient = class {
|
|
|
1194
1263
|
type: options.type,
|
|
1195
1264
|
sort: options.sort ?? ["POPULARITY_DESC"],
|
|
1196
1265
|
page: options.page ?? 1,
|
|
1197
|
-
perPage:
|
|
1266
|
+
perPage: clampPerPage(options.perPage ?? 20)
|
|
1198
1267
|
},
|
|
1199
1268
|
"media"
|
|
1200
1269
|
);
|
|
@@ -1256,7 +1325,7 @@ var AniListClient = class {
|
|
|
1256
1325
|
type: options.type ?? "ANIME",
|
|
1257
1326
|
sort: options.sort ?? ["POPULARITY_DESC"],
|
|
1258
1327
|
page: options.page ?? 1,
|
|
1259
|
-
perPage:
|
|
1328
|
+
perPage: clampPerPage(options.perPage ?? 20)
|
|
1260
1329
|
},
|
|
1261
1330
|
"media"
|
|
1262
1331
|
);
|
|
@@ -1298,7 +1367,7 @@ var AniListClient = class {
|
|
|
1298
1367
|
status: options.status,
|
|
1299
1368
|
sort: options.sort,
|
|
1300
1369
|
page: options.page ?? 1,
|
|
1301
|
-
perPage:
|
|
1370
|
+
perPage: clampPerPage(options.perPage ?? 20)
|
|
1302
1371
|
},
|
|
1303
1372
|
"mediaList"
|
|
1304
1373
|
);
|
|
@@ -1331,7 +1400,7 @@ var AniListClient = class {
|
|
|
1331
1400
|
{
|
|
1332
1401
|
search: options.query,
|
|
1333
1402
|
page: options.page ?? 1,
|
|
1334
|
-
perPage:
|
|
1403
|
+
perPage: clampPerPage(options.perPage ?? 20)
|
|
1335
1404
|
},
|
|
1336
1405
|
"studios"
|
|
1337
1406
|
);
|
|
@@ -1431,23 +1500,14 @@ var AniListClient = class {
|
|
|
1431
1500
|
}
|
|
1432
1501
|
/** @internal */
|
|
1433
1502
|
async executeBatch(ids, buildQuery, prefix) {
|
|
1434
|
-
const chunks =
|
|
1435
|
-
const chunkResults =
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
})
|
|
1441
|
-
);
|
|
1442
|
-
return chunkResults.flat();
|
|
1443
|
-
}
|
|
1444
|
-
/** @internal */
|
|
1445
|
-
chunk(arr, size) {
|
|
1446
|
-
const chunks = [];
|
|
1447
|
-
for (let i = 0; i < arr.length; i += size) {
|
|
1448
|
-
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}`]));
|
|
1449
1509
|
}
|
|
1450
|
-
return
|
|
1510
|
+
return chunkResults.flat();
|
|
1451
1511
|
}
|
|
1452
1512
|
// ── Cache management ──
|
|
1453
1513
|
/**
|
|
@@ -1457,8 +1517,8 @@ var AniListClient = class {
|
|
|
1457
1517
|
await this.cacheAdapter.clear();
|
|
1458
1518
|
}
|
|
1459
1519
|
/**
|
|
1460
|
-
* Number of entries currently in the cache
|
|
1461
|
-
* For async adapters like Redis, this may
|
|
1520
|
+
* Number of entries currently in the cache.
|
|
1521
|
+
* For async adapters like Redis, this may return a Promise.
|
|
1462
1522
|
*/
|
|
1463
1523
|
get cacheSize() {
|
|
1464
1524
|
return this.cacheAdapter.size;
|
|
@@ -1536,15 +1596,14 @@ var RedisCache = class {
|
|
|
1536
1596
|
}
|
|
1537
1597
|
}
|
|
1538
1598
|
/**
|
|
1539
|
-
*
|
|
1540
|
-
* Use `getSize()` for an accurate count.
|
|
1599
|
+
* Get the actual number of keys with this prefix in Redis.
|
|
1541
1600
|
*/
|
|
1542
1601
|
get size() {
|
|
1543
|
-
return
|
|
1602
|
+
return this.getSize();
|
|
1544
1603
|
}
|
|
1545
|
-
/**
|
|
1604
|
+
/** @internal */
|
|
1546
1605
|
async getSize() {
|
|
1547
|
-
const keys = await this.
|
|
1606
|
+
const keys = await this.collectKeys(`${this.prefix}*`);
|
|
1548
1607
|
return keys.length;
|
|
1549
1608
|
}
|
|
1550
1609
|
async keys() {
|