ani-client 2.4.0 → 2.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 +4 -0
- package/dist/cache/redis.d.mts +1 -1
- package/dist/cache/redis.d.ts +1 -1
- package/dist/index.d.mts +72 -4
- package/dist/index.d.ts +72 -4
- package/dist/index.js +120 -32
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +120 -33
- package/dist/index.mjs.map +1 -1
- package/dist/{redis-UeRs8nqC.d.mts → redis-ClB2nNrs.d.mts} +13 -0
- package/dist/{redis-UeRs8nqC.d.ts → redis-ClB2nNrs.d.ts} +13 -0
- package/package.json +10 -9
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
1
7
|
// src/utils/dataloader.ts
|
|
2
8
|
var BatchLoader = class {
|
|
3
|
-
constructor(batchFetch, maxWaitMs = 50) {
|
|
9
|
+
constructor(batchFetch, maxWaitMs = 50, maxBatchSize = 50) {
|
|
4
10
|
this.batchFetch = batchFetch;
|
|
5
11
|
this.maxWaitMs = maxWaitMs;
|
|
12
|
+
this.maxBatchSize = maxBatchSize;
|
|
6
13
|
}
|
|
7
14
|
queue = /* @__PURE__ */ new Map();
|
|
8
15
|
timeout = null;
|
|
@@ -18,10 +25,21 @@ var BatchLoader = class {
|
|
|
18
25
|
this.queue.set(id, callbacks);
|
|
19
26
|
}
|
|
20
27
|
callbacks.push({ resolve, reject });
|
|
28
|
+
if (this.queue.size >= this.maxBatchSize) {
|
|
29
|
+
if (this.timeout) {
|
|
30
|
+
clearTimeout(this.timeout);
|
|
31
|
+
this.timeout = null;
|
|
32
|
+
}
|
|
33
|
+
void this.dispatch();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
21
36
|
if (this.timeout === null) {
|
|
22
|
-
this.timeout = setTimeout(() =>
|
|
23
|
-
|
|
24
|
-
|
|
37
|
+
this.timeout = setTimeout(() => {
|
|
38
|
+
void this.dispatch();
|
|
39
|
+
}, this.maxWaitMs);
|
|
40
|
+
const timer = this.timeout;
|
|
41
|
+
if (typeof timer.unref === "function") {
|
|
42
|
+
timer.unref();
|
|
25
43
|
}
|
|
26
44
|
}
|
|
27
45
|
});
|
|
@@ -630,6 +648,25 @@ var AniListError = class _AniListError extends Error {
|
|
|
630
648
|
};
|
|
631
649
|
|
|
632
650
|
// src/queries/fragments.ts
|
|
651
|
+
var fragments_exports = {};
|
|
652
|
+
__export(fragments_exports, {
|
|
653
|
+
CHARACTER_FIELDS: () => CHARACTER_FIELDS,
|
|
654
|
+
CHARACTER_FIELDS_COMPACT: () => CHARACTER_FIELDS_COMPACT,
|
|
655
|
+
CHARACTER_FIELDS_WITH_VA: () => CHARACTER_FIELDS_WITH_VA,
|
|
656
|
+
MEDIA_FIELDS: () => MEDIA_FIELDS,
|
|
657
|
+
MEDIA_FIELDS_BASE: () => MEDIA_FIELDS_BASE,
|
|
658
|
+
MEDIA_FIELDS_LIGHT: () => MEDIA_FIELDS_LIGHT,
|
|
659
|
+
MEDIA_LIST_FIELDS: () => MEDIA_LIST_FIELDS,
|
|
660
|
+
MEDIA_RECOMMENDATION_FIELDS: () => MEDIA_RECOMMENDATION_FIELDS,
|
|
661
|
+
RELATIONS_FIELDS: () => RELATIONS_FIELDS,
|
|
662
|
+
STAFF_FIELDS: () => STAFF_FIELDS,
|
|
663
|
+
STAFF_MEDIA_FIELDS: () => STAFF_MEDIA_FIELDS,
|
|
664
|
+
STUDIO_FIELDS: () => STUDIO_FIELDS,
|
|
665
|
+
THREAD_FIELDS: () => THREAD_FIELDS,
|
|
666
|
+
USER_FAVORITES_FIELDS: () => USER_FAVORITES_FIELDS,
|
|
667
|
+
USER_FIELDS: () => USER_FIELDS,
|
|
668
|
+
VOICE_ACTOR_FIELDS_COMPACT: () => VOICE_ACTOR_FIELDS_COMPACT
|
|
669
|
+
});
|
|
633
670
|
var MEDIA_FIELDS_LIGHT = `
|
|
634
671
|
__typename
|
|
635
672
|
id
|
|
@@ -1320,6 +1357,9 @@ function buildMediaIncludeQuery(include) {
|
|
|
1320
1357
|
statusDistribution { status amount }
|
|
1321
1358
|
}`);
|
|
1322
1359
|
}
|
|
1360
|
+
if (include.customFields) {
|
|
1361
|
+
extra.push(include.customFields);
|
|
1362
|
+
}
|
|
1323
1363
|
return extra;
|
|
1324
1364
|
}
|
|
1325
1365
|
function buildMediaByIdQuery(include) {
|
|
@@ -1547,6 +1587,14 @@ query ($id: Int!) {
|
|
|
1547
1587
|
${CHARACTER_FIELDS_WITH_VA}
|
|
1548
1588
|
}
|
|
1549
1589
|
}`;
|
|
1590
|
+
function buildCharacterByIdQuery(include) {
|
|
1591
|
+
if (!include?.customFields) {
|
|
1592
|
+
return include?.voiceActors ? QUERY_CHARACTER_BY_ID_WITH_VA : QUERY_CHARACTER_BY_ID;
|
|
1593
|
+
}
|
|
1594
|
+
const fields = include.voiceActors ? CHARACTER_FIELDS_WITH_VA : CHARACTER_FIELDS;
|
|
1595
|
+
return `query ($id: Int!) { Character(id: $id) { ${fields}
|
|
1596
|
+
${include.customFields} } }`;
|
|
1597
|
+
}
|
|
1550
1598
|
var QUERY_CHARACTER_SEARCH = `
|
|
1551
1599
|
query ($search: String, $sort: [CharacterSort], $page: Int, $perPage: Int) {
|
|
1552
1600
|
Page(page: $page, perPage: $perPage) {
|
|
@@ -1665,6 +1713,15 @@ query ($id: Int!, $perPage: Int) {
|
|
|
1665
1713
|
${STAFF_MEDIA_FIELDS}
|
|
1666
1714
|
}
|
|
1667
1715
|
}`;
|
|
1716
|
+
function buildStaffByIdQuery(include) {
|
|
1717
|
+
if (!include?.customFields) {
|
|
1718
|
+
return include?.characterRoles || include?.media ? QUERY_STAFF_BY_ID_WITH_MEDIA : QUERY_STAFF_BY_ID;
|
|
1719
|
+
}
|
|
1720
|
+
const extra = include?.characterRoles || include?.media ? `
|
|
1721
|
+
${STAFF_MEDIA_FIELDS}` : "";
|
|
1722
|
+
return `query ($id: Int!, $perPage: Int) { Staff(id: $id) { ${STAFF_FIELDS}${extra}
|
|
1723
|
+
${include.customFields} } }`;
|
|
1724
|
+
}
|
|
1668
1725
|
var QUERY_STAFF_SEARCH = `
|
|
1669
1726
|
query ($search: String, $sort: [StaffSort], $page: Int, $perPage: Int) {
|
|
1670
1727
|
Page(page: $page, perPage: $perPage) {
|
|
@@ -1682,9 +1739,15 @@ query ($id: Int!) {
|
|
|
1682
1739
|
${STUDIO_FIELDS}
|
|
1683
1740
|
}
|
|
1684
1741
|
}`;
|
|
1685
|
-
function buildStudioByIdQuery(
|
|
1686
|
-
|
|
1687
|
-
|
|
1742
|
+
function buildStudioByIdQuery(include) {
|
|
1743
|
+
const custom = include?.customFields ? `
|
|
1744
|
+
${include.customFields}` : "";
|
|
1745
|
+
if (!include?.media) {
|
|
1746
|
+
if (!custom) return QUERY_STUDIO_BY_ID;
|
|
1747
|
+
return `query ($id: Int!) { Studio(id: $id) { ${STUDIO_FIELDS}${custom} } }`;
|
|
1748
|
+
}
|
|
1749
|
+
const mediaOpts = typeof include.media === "object" ? include.media : {};
|
|
1750
|
+
const pp = clampPerPage(mediaOpts.perPage ?? 25);
|
|
1688
1751
|
return `
|
|
1689
1752
|
query ($id: Int!) {
|
|
1690
1753
|
Studio(id: $id) {
|
|
@@ -1698,7 +1761,7 @@ query ($id: Int!) {
|
|
|
1698
1761
|
nodes {
|
|
1699
1762
|
${MEDIA_FIELDS_LIGHT}
|
|
1700
1763
|
}
|
|
1701
|
-
}
|
|
1764
|
+
}${custom}
|
|
1702
1765
|
}
|
|
1703
1766
|
}`;
|
|
1704
1767
|
}
|
|
@@ -1981,7 +2044,7 @@ function isNetworkError(err) {
|
|
|
1981
2044
|
// src/client/character.ts
|
|
1982
2045
|
async function getCharacter(client, id, include) {
|
|
1983
2046
|
validateId(id, "characterId");
|
|
1984
|
-
const query = include
|
|
2047
|
+
const query = buildCharacterByIdQuery(include);
|
|
1985
2048
|
const data = await client.request(query, { id });
|
|
1986
2049
|
return data.Character;
|
|
1987
2050
|
}
|
|
@@ -2458,12 +2521,13 @@ async function searchReviews(client, options = {}) {
|
|
|
2458
2521
|
// src/client/staff.ts
|
|
2459
2522
|
async function getStaff(client, id, include) {
|
|
2460
2523
|
validateId(id, "staffId");
|
|
2461
|
-
|
|
2524
|
+
const query = buildStaffByIdQuery(include);
|
|
2525
|
+
if (include?.characterRoles || include?.media) {
|
|
2462
2526
|
const perPage = typeof include.media === "object" ? include.media.perPage ?? 25 : 25;
|
|
2463
|
-
const data2 = await client.request(
|
|
2527
|
+
const data2 = await client.request(query, { id, perPage });
|
|
2464
2528
|
return data2.Staff;
|
|
2465
2529
|
}
|
|
2466
|
-
const data = await client.request(
|
|
2530
|
+
const data = await client.request(query, { id });
|
|
2467
2531
|
return data.Staff;
|
|
2468
2532
|
}
|
|
2469
2533
|
async function searchStaff(client, options = {}) {
|
|
@@ -2478,13 +2542,8 @@ async function searchStaff(client, options = {}) {
|
|
|
2478
2542
|
// src/client/studio.ts
|
|
2479
2543
|
async function getStudio(client, id, include) {
|
|
2480
2544
|
validateId(id, "studioId");
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
const query = buildStudioByIdQuery(perPage);
|
|
2484
|
-
const data2 = await client.request(query, { id });
|
|
2485
|
-
return data2.Studio;
|
|
2486
|
-
}
|
|
2487
|
-
const data = await client.request(QUERY_STUDIO_BY_ID, { id });
|
|
2545
|
+
const query = buildStudioByIdQuery(include);
|
|
2546
|
+
const data = await client.request(query, { id });
|
|
2488
2547
|
return data.Studio;
|
|
2489
2548
|
}
|
|
2490
2549
|
async function searchStudios(client, options = {}) {
|
|
@@ -2586,7 +2645,7 @@ function mapFavorites(fav) {
|
|
|
2586
2645
|
|
|
2587
2646
|
// src/client/index.ts
|
|
2588
2647
|
var DEFAULT_API_URL = "https://graphql.anilist.co";
|
|
2589
|
-
var LIB_VERSION = "2.
|
|
2648
|
+
var LIB_VERSION = "2.5.0" ;
|
|
2590
2649
|
var AniListClient = class {
|
|
2591
2650
|
apiUrl;
|
|
2592
2651
|
headers;
|
|
@@ -2601,6 +2660,7 @@ var AniListClient = class {
|
|
|
2601
2660
|
mediaLoader;
|
|
2602
2661
|
characterLoader;
|
|
2603
2662
|
staffLoader;
|
|
2663
|
+
batchingEnabled;
|
|
2604
2664
|
constructor(options = {}) {
|
|
2605
2665
|
this.apiUrl = options.apiUrl ?? DEFAULT_API_URL;
|
|
2606
2666
|
this.headers = {
|
|
@@ -2616,9 +2676,12 @@ var AniListClient = class {
|
|
|
2616
2676
|
this.hooks = options.hooks ?? {};
|
|
2617
2677
|
this.logger = options.logger;
|
|
2618
2678
|
this.signal = options.signal;
|
|
2619
|
-
this.
|
|
2620
|
-
|
|
2621
|
-
|
|
2679
|
+
this.batchingEnabled = options.batching?.enabled ?? true;
|
|
2680
|
+
const windowMs = options.batching?.windowMs ?? 50;
|
|
2681
|
+
const maxBatchSize = options.batching?.maxBatchSize ?? 50;
|
|
2682
|
+
this.mediaLoader = new BatchLoader((ids) => this.getMediaBatch(ids), windowMs, maxBatchSize);
|
|
2683
|
+
this.characterLoader = new BatchLoader((ids) => this.getCharacterBatch(ids), windowMs, maxBatchSize);
|
|
2684
|
+
this.staffLoader = new BatchLoader((ids) => this.getStaffBatch(ids), windowMs, maxBatchSize);
|
|
2622
2685
|
}
|
|
2623
2686
|
/**
|
|
2624
2687
|
* The current rate limit information from the last API response.
|
|
@@ -2721,6 +2784,17 @@ var AniListClient = class {
|
|
|
2721
2784
|
remaining: Number.parseInt(rlRemaining, 10),
|
|
2722
2785
|
reset: Number.parseInt(rlReset, 10)
|
|
2723
2786
|
};
|
|
2787
|
+
const remainingPercent = this._rateLimitInfo.remaining / this._rateLimitInfo.limit;
|
|
2788
|
+
if (remainingPercent <= 0.15) {
|
|
2789
|
+
const resetIn = this._rateLimitInfo.reset - Math.floor(Date.now() / 1e3);
|
|
2790
|
+
const resetInSeconds = resetIn > 0 ? resetIn : 0;
|
|
2791
|
+
this.logger?.warn("Smart Alert: AniList API rate limit is critically low", {
|
|
2792
|
+
remaining: this._rateLimitInfo.remaining,
|
|
2793
|
+
limit: this._rateLimitInfo.limit,
|
|
2794
|
+
resetInSeconds
|
|
2795
|
+
});
|
|
2796
|
+
this.hooks.onRateLimitAlert?.(this._rateLimitInfo.remaining, resetInSeconds);
|
|
2797
|
+
}
|
|
2724
2798
|
}
|
|
2725
2799
|
const durationMs = Date.now() - start;
|
|
2726
2800
|
const data = json.data;
|
|
@@ -2749,10 +2823,10 @@ var AniListClient = class {
|
|
|
2749
2823
|
* @param include - Optional related data to include
|
|
2750
2824
|
*/
|
|
2751
2825
|
async getMedia(id, include) {
|
|
2752
|
-
if (!include) {
|
|
2753
|
-
return this
|
|
2826
|
+
if (!this.batchingEnabled || include) {
|
|
2827
|
+
return getMedia(this, id, include);
|
|
2754
2828
|
}
|
|
2755
|
-
return
|
|
2829
|
+
return this.mediaLoader.load(id);
|
|
2756
2830
|
}
|
|
2757
2831
|
async getMediaCharacters(mediaId, options = {}) {
|
|
2758
2832
|
return getMediaCharacters(this, mediaId, options);
|
|
@@ -2820,10 +2894,10 @@ var AniListClient = class {
|
|
|
2820
2894
|
}
|
|
2821
2895
|
/** Fetch a character by AniList ID. Pass `{ voiceActors: true }` to include VA data. */
|
|
2822
2896
|
async getCharacter(id, include) {
|
|
2823
|
-
if (!include) {
|
|
2824
|
-
return this
|
|
2897
|
+
if (!this.batchingEnabled || include) {
|
|
2898
|
+
return getCharacter(this, id, include);
|
|
2825
2899
|
}
|
|
2826
|
-
return
|
|
2900
|
+
return this.characterLoader.load(id);
|
|
2827
2901
|
}
|
|
2828
2902
|
/** Search for characters by name. */
|
|
2829
2903
|
async searchCharacters(options = {}) {
|
|
@@ -2831,10 +2905,10 @@ var AniListClient = class {
|
|
|
2831
2905
|
}
|
|
2832
2906
|
/** Fetch a staff member by AniList ID. Pass `{ media: true }` or `{ media: { perPage } }` for media credits. */
|
|
2833
2907
|
async getStaff(id, include) {
|
|
2834
|
-
if (!include) {
|
|
2835
|
-
return this
|
|
2908
|
+
if (!this.batchingEnabled || include) {
|
|
2909
|
+
return getStaff(this, id, include);
|
|
2836
2910
|
}
|
|
2837
|
-
return
|
|
2911
|
+
return this.staffLoader.load(id);
|
|
2838
2912
|
}
|
|
2839
2913
|
/** Search for staff (voice actors, directors, etc.). */
|
|
2840
2914
|
async searchStaff(options = {}) {
|
|
@@ -2948,6 +3022,19 @@ var AniListClient = class {
|
|
|
2948
3022
|
page++;
|
|
2949
3023
|
}
|
|
2950
3024
|
}
|
|
3025
|
+
/**
|
|
3026
|
+
* Utility to fetch all pages of a paginated request and return them as a single array.
|
|
3027
|
+
*
|
|
3028
|
+
* @param fetchPage - A function that takes a page number and returns a `PagedResult<T>`
|
|
3029
|
+
* @param maxPages - Maximum number of pages to fetch (default: Infinity)
|
|
3030
|
+
*/
|
|
3031
|
+
async fetchAll(fetchPage, maxPages = Number.POSITIVE_INFINITY) {
|
|
3032
|
+
const results = [];
|
|
3033
|
+
for await (const item of this.paginate(fetchPage, maxPages)) {
|
|
3034
|
+
results.push(item);
|
|
3035
|
+
}
|
|
3036
|
+
return results;
|
|
3037
|
+
}
|
|
2951
3038
|
/** Fetch multiple media entries in a single API request. */
|
|
2952
3039
|
async getMediaBatch(ids) {
|
|
2953
3040
|
if (ids.length === 0) return [];
|
|
@@ -3035,6 +3122,6 @@ var AniListClient = class {
|
|
|
3035
3122
|
}
|
|
3036
3123
|
};
|
|
3037
3124
|
|
|
3038
|
-
export { AiringSort, AniListClient, AniListError, CharacterRole, CharacterSort, MediaFormat, MediaListSort, MediaListStatus, MediaRelationType, MediaSeason, MediaSort, MediaSource, MediaStatus, MediaType, MemoryCache, NormalizedCache, RateLimiter, RecommendationSort, RedisCache, ReviewSort, StaffSort, StudioSort, ThreadSort, UserSort, parseAniListMarkdown };
|
|
3125
|
+
export { AiringSort, AniListClient, AniListError, CharacterRole, CharacterSort, fragments_exports as Fragments, MediaFormat, MediaListSort, MediaListStatus, MediaRelationType, MediaSeason, MediaSort, MediaSource, MediaStatus, MediaType, MemoryCache, NormalizedCache, RateLimiter, RecommendationSort, RedisCache, ReviewSort, StaffSort, StudioSort, ThreadSort, UserSort, parseAniListMarkdown };
|
|
3039
3126
|
//# sourceMappingURL=index.mjs.map
|
|
3040
3127
|
//# sourceMappingURL=index.mjs.map
|