ani-client 1.6.1 → 1.8.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 +104 -44
- package/dist/index.d.mts +146 -56
- package/dist/index.d.ts +146 -56
- package/dist/index.js +384 -84
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +384 -85
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,39 +1,40 @@
|
|
|
1
|
-
# ani-client
|
|
1
|
+
# ani-client
|
|
2
2
|
|
|
3
3
|

|
|
4
|
+
|
|
4
5
|
[](https://github.com/gonzyui/ani-client/actions/workflows/ci.yml)
|
|
5
|
-
[](https://www.npmjs.com/package/ani-client)
|
|
6
|
+
[](https://www.npmjs.com/package/ani-client)
|
|
7
|
+
[](https://www.npmjs.com/package/ani-client)
|
|
8
|
+
[](https://bundlephobia.com/package/ani-client)
|
|
9
|
+
[](https://www.typescriptlang.org/)
|
|
6
10
|
[](LICENSE)
|
|
7
11
|
|
|
8
|
-
> A
|
|
9
|
-
|
|
10
|
-
✨ **Showcase**: [Check here](https://ani-client.js.org/showcase) to see which projects use this package!
|
|
11
|
-
|
|
12
|
-
- **Zero dependencies** — uses the native `fetch` API
|
|
13
|
-
- **Universal** — Node.js ≥ 20, Bun, Deno and modern browsers
|
|
14
|
-
- **Dual format** — ships ESM + CJS with full TypeScript declarations
|
|
15
|
-
- **Reliable** — Built-in caching, Rate-limit protections with exponential backoff, automatic retries & request deduplication!
|
|
12
|
+
> A fully typed, zero-dependency client for the [AniList](https://anilist.co) GraphQL API.
|
|
16
13
|
|
|
17
|
-
|
|
14
|
+
✨ **Showcase**: [See who's using ani-client](https://ani-client.js.org/showcase)
|
|
18
15
|
|
|
19
|
-
|
|
16
|
+
## Highlights
|
|
20
17
|
|
|
21
|
-
**
|
|
18
|
+
- **Zero dependencies** — uses the native `fetch` API
|
|
19
|
+
- **Universal** — Node.js ≥ 20, Bun, Deno, and modern browsers
|
|
20
|
+
- **Dual format** — ships ESM + CJS with full `.d.ts` declarations
|
|
21
|
+
- **LRU cache** with TTL, stale-while-revalidate, and hit/miss stats
|
|
22
|
+
- **Rate-limit protection** with exponential backoff, retries, and custom strategies
|
|
23
|
+
- **Request deduplication** — concurrent identical queries share a single in-flight request
|
|
24
|
+
- **Batch queries** — fetch up to 50 media/characters/staff in one API call
|
|
25
|
+
- **Auto-pagination** — async iterator that yields items across pages
|
|
26
|
+
- **AbortSignal support** — cancel globally or per-request with `withSignal()`
|
|
27
|
+
- **Injectable logger** — plug in `console`, pino, winston, or any compatible logger
|
|
28
|
+
- **Redis-ready** — swap the cache adapter with the built-in `RedisCache` for distributed setups
|
|
22
29
|
|
|
23
30
|
## Install
|
|
24
31
|
|
|
25
32
|
```bash
|
|
26
|
-
# npm
|
|
27
33
|
npm install ani-client
|
|
28
|
-
|
|
29
|
-
# pnpm
|
|
34
|
+
# or
|
|
30
35
|
pnpm add ani-client
|
|
31
|
-
|
|
32
|
-
# yarn
|
|
36
|
+
# or
|
|
33
37
|
yarn add ani-client
|
|
34
|
-
|
|
35
|
-
# bun
|
|
36
|
-
bun add ani-client
|
|
37
38
|
```
|
|
38
39
|
|
|
39
40
|
## Quick start
|
|
@@ -43,59 +44,118 @@ import { AniListClient, MediaType } from "ani-client";
|
|
|
43
44
|
|
|
44
45
|
const client = new AniListClient();
|
|
45
46
|
|
|
46
|
-
//
|
|
47
|
-
const
|
|
48
|
-
console.log(
|
|
47
|
+
// Fetch an anime by AniList ID
|
|
48
|
+
const bebop = await client.getMedia(1);
|
|
49
|
+
console.log(bebop.title.romaji); // "Cowboy Bebop"
|
|
49
50
|
|
|
50
|
-
// Search
|
|
51
|
+
// Search with filters
|
|
51
52
|
const results = await client.searchMedia({
|
|
52
53
|
query: "Naruto",
|
|
53
54
|
type: MediaType.ANIME,
|
|
54
|
-
|
|
55
|
+
genres: ["Action"],
|
|
56
|
+
perPage: 10,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Cross-platform lookup by MyAnimeList ID
|
|
60
|
+
const fma = await client.getMediaByMalId(5114);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Features at a glance
|
|
64
|
+
|
|
65
|
+
### Caching & stale-while-revalidate
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
const client = new AniListClient({
|
|
69
|
+
cache: {
|
|
70
|
+
ttl: 1000 * 60 * 5, // 5 min TTL
|
|
71
|
+
maxSize: 200, // LRU capacity
|
|
72
|
+
staleWhileRevalidateMs: 60_000, // serve stale for 1 min after expiry
|
|
73
|
+
},
|
|
55
74
|
});
|
|
56
|
-
|
|
75
|
+
|
|
76
|
+
// Check cache performance
|
|
77
|
+
console.log(client.cacheStats);
|
|
78
|
+
// { hits: 42, misses: 8, stales: 2, hitRate: 0.84 }
|
|
57
79
|
```
|
|
58
80
|
|
|
59
|
-
###
|
|
81
|
+
### Per-request cancellation
|
|
60
82
|
|
|
61
83
|
```ts
|
|
62
|
-
const
|
|
84
|
+
const controller = new AbortController();
|
|
85
|
+
const scoped = client.withSignal(controller.signal);
|
|
86
|
+
|
|
87
|
+
setTimeout(() => controller.abort(), 3_000);
|
|
88
|
+
const anime = await scoped.getMedia(1);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Structured logging
|
|
63
92
|
|
|
64
|
-
|
|
65
|
-
|
|
93
|
+
```ts
|
|
94
|
+
const client = new AniListClient({ logger: console });
|
|
95
|
+
// debug: "API request" { query: "query { Media(id: 1) { ... } }" }
|
|
96
|
+
// debug: "Request complete" { durationMs: 120, status: 200 }
|
|
66
97
|
```
|
|
67
98
|
|
|
68
|
-
###
|
|
99
|
+
### Rate limiting & retries
|
|
69
100
|
|
|
70
101
|
```ts
|
|
71
102
|
const client = new AniListClient({
|
|
72
103
|
rateLimit: {
|
|
104
|
+
maxRequests: 85,
|
|
105
|
+
windowMs: 60_000,
|
|
106
|
+
maxRetries: 3,
|
|
107
|
+
retryOnNetworkError: true,
|
|
73
108
|
retryStrategy: (attempt) => (attempt + 1) * 1000, // linear backoff
|
|
74
109
|
},
|
|
75
110
|
});
|
|
76
111
|
|
|
77
|
-
|
|
112
|
+
console.log(client.rateLimitInfo);
|
|
113
|
+
// { remaining: 82, limit: 85, reset: 1741104000 }
|
|
114
|
+
```
|
|
78
115
|
|
|
79
|
-
|
|
80
|
-
console.log(`${info?.remaining}/${info?.limit} requests remaining`);
|
|
116
|
+
### Batch & pagination
|
|
81
117
|
|
|
82
|
-
|
|
83
|
-
|
|
118
|
+
```ts
|
|
119
|
+
// Fetch 100 anime in 2 API calls (50 per batch)
|
|
120
|
+
const batch = await client.getMediaBatch([1, 2, 3, /* ...up to 100 IDs */]);
|
|
121
|
+
|
|
122
|
+
// Auto-paginate through all results
|
|
123
|
+
for await (const anime of client.paginate(
|
|
124
|
+
(page) => client.searchMedia({ query: "Gundam", page, perPage: 50 }),
|
|
125
|
+
5, // max 5 pages
|
|
126
|
+
)) {
|
|
127
|
+
console.log(anime.title.romaji);
|
|
128
|
+
}
|
|
84
129
|
```
|
|
85
130
|
|
|
86
|
-
###
|
|
131
|
+
### Users, characters, studios & more
|
|
87
132
|
|
|
88
133
|
```ts
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
await client.
|
|
134
|
+
const user = await client.getUser("AniList");
|
|
135
|
+
const favs = await client.getUserFavorites("AniList", { perPage: 50 });
|
|
136
|
+
const char = await client.getCharacter(1, { voiceActors: true });
|
|
137
|
+
const studio = await client.getStudio(21, { media: { perPage: 50 } });
|
|
138
|
+
const schedule = await client.getWeeklySchedule();
|
|
94
139
|
```
|
|
95
140
|
|
|
141
|
+
## Documentation
|
|
142
|
+
|
|
143
|
+
Full API reference, guides (caching, pagination, includes, hooks, etc.) and configuration examples:
|
|
144
|
+
|
|
145
|
+
**[ani-client.js.org](https://ani-client.js.org)**
|
|
146
|
+
|
|
147
|
+
## Requirements
|
|
148
|
+
|
|
149
|
+
| Runtime | Version |
|
|
150
|
+
| --- | --- |
|
|
151
|
+
| Node.js | ≥ 20 |
|
|
152
|
+
| Bun | ≥ 1.0 |
|
|
153
|
+
| Deno | ≥ 1.28 |
|
|
154
|
+
| Browsers | Any with `fetch` + `AbortController` |
|
|
155
|
+
|
|
96
156
|
## Contributing
|
|
97
157
|
|
|
98
|
-
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, coding standards, and
|
|
158
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, coding standards, and PR guidelines.
|
|
99
159
|
|
|
100
160
|
## License
|
|
101
161
|
|
package/dist/index.d.mts
CHANGED
|
@@ -50,6 +50,12 @@ interface CacheOptions {
|
|
|
50
50
|
maxSize?: number;
|
|
51
51
|
/** Set to false to disable caching entirely */
|
|
52
52
|
enabled?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Stale-while-revalidate grace period in milliseconds (default: 0 = disabled).
|
|
55
|
+
* When set, expired entries are still returned within the grace window,
|
|
56
|
+
* allowing the caller to refresh in the background.
|
|
57
|
+
*/
|
|
58
|
+
staleWhileRevalidateMs?: number;
|
|
53
59
|
}
|
|
54
60
|
/** Rate limiter configuration options. */
|
|
55
61
|
interface RateLimitOptions {
|
|
@@ -111,6 +117,16 @@ interface ResponseMeta {
|
|
|
111
117
|
/** Rate limit information from the API response headers (not present for cached responses). */
|
|
112
118
|
rateLimitInfo?: RateLimitInfo;
|
|
113
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Minimal logger interface for structured log output.
|
|
122
|
+
* Compatible with `console`, `pino`, `winston`, etc.
|
|
123
|
+
*/
|
|
124
|
+
interface Logger {
|
|
125
|
+
debug(message: string, ...args: unknown[]): void;
|
|
126
|
+
info(message: string, ...args: unknown[]): void;
|
|
127
|
+
warn(message: string, ...args: unknown[]): void;
|
|
128
|
+
error(message: string, ...args: unknown[]): void;
|
|
129
|
+
}
|
|
114
130
|
interface AniListClientOptions {
|
|
115
131
|
/** Optional AniList OAuth token for authenticated requests */
|
|
116
132
|
token?: string;
|
|
@@ -126,6 +142,17 @@ interface AniListClientOptions {
|
|
|
126
142
|
hooks?: AniListHooks;
|
|
127
143
|
/** Optional AbortSignal to cancel all requests made by this client */
|
|
128
144
|
signal?: AbortSignal;
|
|
145
|
+
/**
|
|
146
|
+
* Optional logger for structured log output.
|
|
147
|
+
* Accepts any object with `debug`, `info`, `warn`, `error` methods.
|
|
148
|
+
* Compatible with `console`, `pino`, `winston`, etc.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* const client = new AniListClient({ logger: console });
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
logger?: Logger;
|
|
129
156
|
}
|
|
130
157
|
|
|
131
158
|
declare enum StaffSort {
|
|
@@ -225,21 +252,11 @@ interface SearchStaffOptions {
|
|
|
225
252
|
perPage?: number;
|
|
226
253
|
}
|
|
227
254
|
/** Compact voice actor data returned inside character edges. */
|
|
228
|
-
interface VoiceActor {
|
|
229
|
-
|
|
230
|
-
name: {
|
|
231
|
-
first: string | null;
|
|
232
|
-
middle: string | null;
|
|
233
|
-
last: string | null;
|
|
234
|
-
full: string | null;
|
|
235
|
-
native: string | null;
|
|
255
|
+
interface VoiceActor extends Pick<Staff, "id" | "image" | "gender" | "primaryOccupations" | "siteUrl"> {
|
|
256
|
+
name: StaffName & {
|
|
236
257
|
userPreferred: string | null;
|
|
237
258
|
};
|
|
238
259
|
languageV2: string | null;
|
|
239
|
-
image: StaffImage;
|
|
240
|
-
gender: string | null;
|
|
241
|
-
primaryOccupations: string[];
|
|
242
|
-
siteUrl: string | null;
|
|
243
260
|
}
|
|
244
261
|
|
|
245
262
|
declare enum CharacterSort {
|
|
@@ -389,11 +406,31 @@ interface Studio {
|
|
|
389
406
|
interface StudioConnection {
|
|
390
407
|
nodes: Studio[];
|
|
391
408
|
}
|
|
409
|
+
declare enum StudioSort {
|
|
410
|
+
ID = "ID",
|
|
411
|
+
ID_DESC = "ID_DESC",
|
|
412
|
+
NAME = "NAME",
|
|
413
|
+
NAME_DESC = "NAME_DESC",
|
|
414
|
+
SEARCH_MATCH = "SEARCH_MATCH",
|
|
415
|
+
FAVOURITES = "FAVOURITES",
|
|
416
|
+
FAVOURITES_DESC = "FAVOURITES_DESC"
|
|
417
|
+
}
|
|
392
418
|
interface SearchStudioOptions {
|
|
393
419
|
query?: string;
|
|
420
|
+
sort?: StudioSort[];
|
|
394
421
|
page?: number;
|
|
395
422
|
perPage?: number;
|
|
396
423
|
}
|
|
424
|
+
/**
|
|
425
|
+
* Options for controlling embedded media when fetching a single studio.
|
|
426
|
+
* Pass `{ media: { perPage: 50 } }` to fetch more media per studio.
|
|
427
|
+
*/
|
|
428
|
+
interface StudioIncludeOptions {
|
|
429
|
+
/** Customize the number of media returned. `true` = 25 (default), or `{ perPage }`. */
|
|
430
|
+
media?: boolean | {
|
|
431
|
+
perPage?: number;
|
|
432
|
+
};
|
|
433
|
+
}
|
|
397
434
|
|
|
398
435
|
declare enum UserSort {
|
|
399
436
|
ID = "ID",
|
|
@@ -443,18 +480,10 @@ interface SearchUserOptions {
|
|
|
443
480
|
}
|
|
444
481
|
interface FavoriteMediaNode {
|
|
445
482
|
id: number;
|
|
446
|
-
title:
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
userPreferred: string | null;
|
|
451
|
-
};
|
|
452
|
-
coverImage: {
|
|
453
|
-
large: string | null;
|
|
454
|
-
medium: string | null;
|
|
455
|
-
};
|
|
456
|
-
type: string | null;
|
|
457
|
-
format: string | null;
|
|
483
|
+
title: MediaTitle;
|
|
484
|
+
coverImage: Pick<MediaCoverImage, "large" | "medium">;
|
|
485
|
+
type: MediaType | null;
|
|
486
|
+
format: MediaFormat | null;
|
|
458
487
|
siteUrl: string | null;
|
|
459
488
|
}
|
|
460
489
|
interface FavoriteCharacterNode {
|
|
@@ -493,6 +522,13 @@ interface UserFavorites {
|
|
|
493
522
|
staff: FavoriteStaffNode[];
|
|
494
523
|
studios: FavoriteStudioNode[];
|
|
495
524
|
}
|
|
525
|
+
/**
|
|
526
|
+
* Options for controlling the number of results when fetching user favorites.
|
|
527
|
+
*/
|
|
528
|
+
interface UserFavoritesOptions {
|
|
529
|
+
/** Number of items per category (default: 25, max: 50). */
|
|
530
|
+
perPage?: number;
|
|
531
|
+
}
|
|
496
532
|
|
|
497
533
|
declare enum MediaType {
|
|
498
534
|
ANIME = "ANIME",
|
|
@@ -658,7 +694,7 @@ interface ScoreDistribution {
|
|
|
658
694
|
amount: number;
|
|
659
695
|
}
|
|
660
696
|
interface StatusDistribution {
|
|
661
|
-
status: MediaListStatus
|
|
697
|
+
status: MediaListStatus;
|
|
662
698
|
amount: number;
|
|
663
699
|
}
|
|
664
700
|
interface MediaStats {
|
|
@@ -889,17 +925,9 @@ interface ThreadCategory {
|
|
|
889
925
|
}
|
|
890
926
|
interface ThreadMediaCategory {
|
|
891
927
|
id: number;
|
|
892
|
-
title:
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
native: string | null;
|
|
896
|
-
userPreferred: string | null;
|
|
897
|
-
};
|
|
898
|
-
type: string;
|
|
899
|
-
coverImage: {
|
|
900
|
-
large: string | null;
|
|
901
|
-
medium: string | null;
|
|
902
|
-
} | null;
|
|
928
|
+
title: MediaTitle;
|
|
929
|
+
type: MediaType;
|
|
930
|
+
coverImage: Pick<MediaCoverImage, "large" | "medium"> | null;
|
|
903
931
|
siteUrl: string | null;
|
|
904
932
|
}
|
|
905
933
|
/** Sort options for thread queries. */
|
|
@@ -961,6 +989,7 @@ declare class AniListClient {
|
|
|
961
989
|
private readonly cacheAdapter;
|
|
962
990
|
private readonly rateLimiter;
|
|
963
991
|
private readonly hooks;
|
|
992
|
+
private readonly logger?;
|
|
964
993
|
private readonly signal?;
|
|
965
994
|
private readonly inFlight;
|
|
966
995
|
private _rateLimitInfo?;
|
|
@@ -1006,8 +1035,23 @@ declare class AniListClient {
|
|
|
1006
1035
|
getTopRated(type?: MediaType, page?: number, perPage?: number): Promise<PagedResult<Media>>;
|
|
1007
1036
|
/** Get recently aired anime episodes. */
|
|
1008
1037
|
getAiredEpisodes(options?: GetAiringOptions): Promise<PagedResult<AiringSchedule>>;
|
|
1009
|
-
/**
|
|
1038
|
+
/**
|
|
1039
|
+
* Get currently releasing manga sorted by most recently updated.
|
|
1040
|
+
*
|
|
1041
|
+
* @param options - Pagination parameters
|
|
1042
|
+
*/
|
|
1043
|
+
getRecentlyUpdatedManga(options?: GetRecentChaptersOptions): Promise<PagedResult<Media>>;
|
|
1044
|
+
/**
|
|
1045
|
+
* @deprecated Use `getRecentlyUpdatedManga` instead. This alias will be removed in v2.
|
|
1046
|
+
*/
|
|
1010
1047
|
getAiredChapters(options?: GetRecentChaptersOptions): Promise<PagedResult<Media>>;
|
|
1048
|
+
/**
|
|
1049
|
+
* Fetch a media entry by its MyAnimeList (MAL) ID.
|
|
1050
|
+
*
|
|
1051
|
+
* @param malId - The MyAnimeList ID
|
|
1052
|
+
* @param type - Optional media type to disambiguate (some MAL IDs map to both ANIME and MANGA)
|
|
1053
|
+
*/
|
|
1054
|
+
getMediaByMalId(malId: number, type?: MediaType): Promise<Media>;
|
|
1011
1055
|
/** Get the detailed schedule for the current week, sorted by day. */
|
|
1012
1056
|
getWeeklySchedule(date?: Date): Promise<WeeklySchedule>;
|
|
1013
1057
|
/** Get upcoming (not yet released) media. */
|
|
@@ -1038,17 +1082,29 @@ declare class AniListClient {
|
|
|
1038
1082
|
* Fetch a user's favorite anime, manga, characters, staff, and studios.
|
|
1039
1083
|
*
|
|
1040
1084
|
* @param idOrName - AniList user ID (number) or username (string)
|
|
1085
|
+
* @param options - Optional pagination options (perPage per category)
|
|
1041
1086
|
* @returns The user's favorites grouped by category
|
|
1042
1087
|
*
|
|
1043
1088
|
* @example
|
|
1044
1089
|
* ```typescript
|
|
1045
1090
|
* const favs = await client.getUserFavorites("AniList");
|
|
1046
1091
|
* favs.anime.forEach(a => console.log(a.title.romaji));
|
|
1092
|
+
*
|
|
1093
|
+
* // Fetch more results per category
|
|
1094
|
+
* const moreResults = await client.getUserFavorites(1, { perPage: 50 });
|
|
1047
1095
|
* ```
|
|
1048
1096
|
*/
|
|
1049
|
-
getUserFavorites(idOrName: number | string): Promise<UserFavorites>;
|
|
1050
|
-
/**
|
|
1051
|
-
|
|
1097
|
+
getUserFavorites(idOrName: number | string, options?: UserFavoritesOptions): Promise<UserFavorites>;
|
|
1098
|
+
/**
|
|
1099
|
+
* Fetch a studio by its AniList ID.
|
|
1100
|
+
* Pass `include` to customise the number of media returned.
|
|
1101
|
+
*
|
|
1102
|
+
* @example
|
|
1103
|
+
* ```typescript
|
|
1104
|
+
* const studio = await client.getStudio(21, { media: { perPage: 50 } });
|
|
1105
|
+
* ```
|
|
1106
|
+
*/
|
|
1107
|
+
getStudio(id: number, include?: StudioIncludeOptions): Promise<Studio>;
|
|
1052
1108
|
/** Search for studios by name. */
|
|
1053
1109
|
searchStudios(options?: SearchStudioOptions): Promise<PagedResult<Studio>>;
|
|
1054
1110
|
/** Fetch a forum thread by its AniList ID. */
|
|
@@ -1084,6 +1140,20 @@ declare class AniListClient {
|
|
|
1084
1140
|
invalidateCache(pattern: string | RegExp): Promise<number>;
|
|
1085
1141
|
/** Clean up resources held by the client. */
|
|
1086
1142
|
destroy(): Promise<void>;
|
|
1143
|
+
/**
|
|
1144
|
+
* Return a scoped view of this client where every request uses the given `AbortSignal`.
|
|
1145
|
+
* The returned object shares the same cache, rate limiter, and hooks.
|
|
1146
|
+
*
|
|
1147
|
+
* @example
|
|
1148
|
+
* ```ts
|
|
1149
|
+
* const controller = new AbortController();
|
|
1150
|
+
* const media = await client.withSignal(controller.signal).getMedia(1);
|
|
1151
|
+
*
|
|
1152
|
+
* // Cancel all in-flight requests made through the scoped view
|
|
1153
|
+
* controller.abort();
|
|
1154
|
+
* ```
|
|
1155
|
+
*/
|
|
1156
|
+
withSignal(signal: AbortSignal): AniListClient;
|
|
1087
1157
|
}
|
|
1088
1158
|
|
|
1089
1159
|
/**
|
|
@@ -1097,26 +1167,59 @@ declare class AniListError extends Error {
|
|
|
1097
1167
|
constructor(message: string, status: number, errors?: unknown[]);
|
|
1098
1168
|
}
|
|
1099
1169
|
|
|
1170
|
+
/** Cache performance statistics. */
|
|
1171
|
+
interface CacheStats {
|
|
1172
|
+
/** Total cache hits. */
|
|
1173
|
+
hits: number;
|
|
1174
|
+
/** Total cache misses. */
|
|
1175
|
+
misses: number;
|
|
1176
|
+
/** Stale entries returned (only with stale-while-revalidate). */
|
|
1177
|
+
stales: number;
|
|
1178
|
+
/** Hit rate as a ratio 0–1 (NaN if no requests yet). */
|
|
1179
|
+
hitRate: number;
|
|
1180
|
+
}
|
|
1100
1181
|
declare class MemoryCache implements CacheAdapter {
|
|
1101
1182
|
private readonly ttl;
|
|
1102
1183
|
private readonly maxSize;
|
|
1103
1184
|
private readonly enabled;
|
|
1185
|
+
private readonly swrMs;
|
|
1104
1186
|
private readonly store;
|
|
1187
|
+
private _hits;
|
|
1188
|
+
private _misses;
|
|
1189
|
+
private _stales;
|
|
1105
1190
|
constructor(options?: CacheOptions);
|
|
1106
1191
|
/** Build a deterministic cache key from a query + variables pair. */
|
|
1107
1192
|
static key(query: string, variables: Record<string, unknown>): string;
|
|
1108
|
-
/**
|
|
1193
|
+
/**
|
|
1194
|
+
* Retrieve a cached value, or `undefined` if missing / expired.
|
|
1195
|
+
* With stale-while-revalidate enabled, returns stale data within the grace window
|
|
1196
|
+
* and flags it so the caller can refresh in the background.
|
|
1197
|
+
*/
|
|
1109
1198
|
get<T>(key: string): T | undefined;
|
|
1110
1199
|
/** Store a value in the cache. */
|
|
1111
1200
|
set<T>(key: string, data: T): void;
|
|
1112
1201
|
/** Remove a specific entry. */
|
|
1113
1202
|
delete(key: string): boolean;
|
|
1114
|
-
/** Clear the entire cache. */
|
|
1203
|
+
/** Clear the entire cache and reset statistics. */
|
|
1115
1204
|
clear(): void;
|
|
1116
1205
|
/** Number of entries currently stored. */
|
|
1117
1206
|
get size(): number | Promise<number>;
|
|
1118
1207
|
/** Return all cache keys. */
|
|
1119
1208
|
keys(): string[];
|
|
1209
|
+
/**
|
|
1210
|
+
* Get cache performance statistics.
|
|
1211
|
+
*
|
|
1212
|
+
* @example
|
|
1213
|
+
* ```ts
|
|
1214
|
+
* const cache = new MemoryCache();
|
|
1215
|
+
* // ... after some usage ...
|
|
1216
|
+
* console.log(cache.stats);
|
|
1217
|
+
* // { hits: 42, misses: 8, stales: 0, hitRate: 0.84 }
|
|
1218
|
+
* ```
|
|
1219
|
+
*/
|
|
1220
|
+
get stats(): CacheStats;
|
|
1221
|
+
/** Reset cache statistics without clearing stored data. */
|
|
1222
|
+
resetStats(): void;
|
|
1120
1223
|
/**
|
|
1121
1224
|
* Remove all entries whose key matches the given pattern.
|
|
1122
1225
|
*
|
|
@@ -1245,19 +1348,6 @@ declare class RateLimiter {
|
|
|
1245
1348
|
dispose(): void;
|
|
1246
1349
|
}
|
|
1247
1350
|
|
|
1248
|
-
/**
|
|
1249
|
-
* Parses AniList specific markdown into standard HTML.
|
|
1250
|
-
* Includes formatting for spoilers, images, videos (youtube/webm), headings,
|
|
1251
|
-
* lists, code blocks, and standard markdown elements.
|
|
1252
|
-
*
|
|
1253
|
-
* @security This function escapes HTML entities to prevent XSS attacks.
|
|
1254
|
-
* However, the output is still raw HTML — consumers should always use a
|
|
1255
|
-
* Content Security Policy and consider additional sanitization when rendering
|
|
1256
|
-
* user-generated content in a browser.
|
|
1257
|
-
*
|
|
1258
|
-
* @param text The AniList markdown text to parse
|
|
1259
|
-
* @returns The parsed HTML string
|
|
1260
|
-
*/
|
|
1261
1351
|
declare function parseAniListMarkdown(text: string): string;
|
|
1262
1352
|
|
|
1263
|
-
export { type AiringSchedule, AiringSort, AniListClient, type AniListClientOptions, AniListError, type AniListHooks, type CacheAdapter, type CacheOptions, type Character, type CharacterImage, type CharacterIncludeOptions, type CharacterMediaEdge, type CharacterName, CharacterRole, CharacterSort, type DayOfWeek, type ExternalLink, type FavoriteCharacterNode, type FavoriteMediaNode, type FavoriteStaffNode, type FavoriteStudioNode, type FuzzyDate, type GetAiringOptions, type GetPlanningOptions, type GetRecentChaptersOptions, type GetRecommendationsOptions, type GetSeasonOptions, type GetUserMediaListOptions, type Media, type MediaCharacterConnection, type MediaCharacterEdge, type MediaConnection, type MediaCoverImage, type MediaEdge, MediaFormat, type MediaIncludeOptions, type MediaListEntry, MediaListSort, MediaListStatus, type MediaRecommendationNode, MediaRelationType, MediaSeason, MediaSort, MediaSource, type MediaStaffConnection, type MediaStaffEdge, type MediaStats, MediaStatus, type MediaTag, type MediaTitle, type MediaTrailer, MediaType, MemoryCache, type NextAiringEpisode, type PageInfo, type PagedResult, type RateLimitInfo, type RateLimitOptions, RateLimiter, type Recommendation, RecommendationSort, RedisCache, type RedisCacheOptions, type RedisLikeClient, type ResponseMeta, type ScoreDistribution, type SearchCharacterOptions, type SearchMediaOptions, type SearchStaffOptions, type SearchStudioOptions, type SearchThreadOptions, type SearchUserOptions, type Staff, type StaffImage, type StaffIncludeOptions, type StaffMediaNode, type StaffName, StaffSort, type StatusDistribution, type StreamingEpisode, type Studio, type StudioConnection, type Thread, type ThreadCategory, type ThreadMediaCategory, ThreadSort, type User, type UserAvatar, type UserFavorites, UserSort, type UserStatistics, type VoiceActor, type WeeklySchedule, parseAniListMarkdown };
|
|
1353
|
+
export { type AiringSchedule, AiringSort, AniListClient, type AniListClientOptions, AniListError, type AniListHooks, type CacheAdapter, type CacheOptions, type CacheStats, type Character, type CharacterImage, type CharacterIncludeOptions, type CharacterMediaEdge, type CharacterName, CharacterRole, CharacterSort, type DayOfWeek, type ExternalLink, type FavoriteCharacterNode, type FavoriteMediaNode, type FavoriteStaffNode, type FavoriteStudioNode, type FuzzyDate, type GetAiringOptions, type GetPlanningOptions, type GetRecentChaptersOptions, type GetRecommendationsOptions, type GetSeasonOptions, type GetUserMediaListOptions, type Logger, type Media, type MediaCharacterConnection, type MediaCharacterEdge, type MediaConnection, type MediaCoverImage, type MediaEdge, MediaFormat, type MediaIncludeOptions, type MediaListEntry, MediaListSort, MediaListStatus, type MediaRecommendationNode, MediaRelationType, MediaSeason, MediaSort, MediaSource, type MediaStaffConnection, type MediaStaffEdge, type MediaStats, MediaStatus, type MediaTag, type MediaTitle, type MediaTrailer, MediaType, MemoryCache, type NextAiringEpisode, type PageInfo, type PagedResult, type RateLimitInfo, type RateLimitOptions, RateLimiter, type Recommendation, RecommendationSort, RedisCache, type RedisCacheOptions, type RedisLikeClient, type ResponseMeta, type ScoreDistribution, type SearchCharacterOptions, type SearchMediaOptions, type SearchStaffOptions, type SearchStudioOptions, type SearchThreadOptions, type SearchUserOptions, type Staff, type StaffImage, type StaffIncludeOptions, type StaffMediaNode, type StaffName, StaffSort, type StatusDistribution, type StreamingEpisode, type Studio, type StudioConnection, type StudioIncludeOptions, StudioSort, type Thread, type ThreadCategory, type ThreadMediaCategory, ThreadSort, type User, type UserAvatar, type UserFavorites, type UserFavoritesOptions, UserSort, type UserStatistics, type VoiceActor, type WeeklySchedule, parseAniListMarkdown };
|