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 CHANGED
@@ -1,39 +1,40 @@
1
- # ani-client
1
+ # ani-client
2
2
 
3
3
  ![ani-client logo](docs/public/assets/logo.png)
4
+
4
5
  [![CI](https://github.com/gonzyui/ani-client/actions/workflows/ci.yml/badge.svg)](https://github.com/gonzyui/ani-client/actions/workflows/ci.yml)
5
- [![npm](https://img.shields.io/npm/v/ani-client)](https://www.npmjs.com/package/ani-client)
6
+ [![npm version](https://img.shields.io/npm/v/ani-client)](https://www.npmjs.com/package/ani-client)
7
+ [![npm downloads](https://img.shields.io/npm/dm/ani-client)](https://www.npmjs.com/package/ani-client)
8
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/ani-client)](https://bundlephobia.com/package/ani-client)
9
+ [![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue)](https://www.typescriptlang.org/)
6
10
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
11
 
8
- > A simple, typed client to fetch anime, manga, character, staff and user data from [AniList](https://anilist.co).
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
- ## 📖 Documentation
14
+ **Showcase**: [See who's using ani-client](https://ani-client.js.org/showcase)
18
15
 
19
- The full API reference, usage guide, and configuration examples are available on our official documentation website!
16
+ ## Highlights
20
17
 
21
- **[👉 View the full documentation here](https://ani-client.js.org)**
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
- // Get an anime by ID
47
- const cowboyBebop = await client.getMedia(1);
48
- console.log(cowboyBebop.title.romaji); // "Cowboy Bebop"
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 for anime
51
+ // Search with filters
51
52
  const results = await client.searchMedia({
52
53
  query: "Naruto",
53
54
  type: MediaType.ANIME,
54
- perPage: 5,
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
- console.log(results.results.map((m) => m.title.english));
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
- ### Fetch user favorites
81
+ ### Per-request cancellation
60
82
 
61
83
  ```ts
62
- const favs = await client.getUserFavorites("AniList");
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
- favs.anime.forEach((a) => console.log(a.title.romaji));
65
- favs.characters.forEach((c) => console.log(c.name.full));
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
- ### Monitor rate limits
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
- await client.getMedia(1);
112
+ console.log(client.rateLimitInfo);
113
+ // { remaining: 82, limit: 85, reset: 1741104000 }
114
+ ```
78
115
 
79
- const info = client.rateLimitInfo;
80
- console.log(`${info?.remaining}/${info?.limit} requests remaining`);
116
+ ### Batch & pagination
81
117
 
82
- const meta = client.lastRequestMeta;
83
- console.log(`${meta?.durationMs}ms, cache: ${meta?.fromCache}`);
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
- ### Cancel requests
131
+ ### Users, characters, studios & more
87
132
 
88
133
  ```ts
89
- const controller = new AbortController();
90
- const client = new AniListClient({ signal: controller.signal });
91
-
92
- setTimeout(() => controller.abort(), 5_000);
93
- await client.getMedia(1); // aborted after 5s
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 how to submit changes.
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
- id: number;
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
- romaji: string | null;
448
- english: string | null;
449
- native: string | null;
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 | string;
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
- romaji: string | null;
894
- english: string | null;
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
- /** Get currently releasing manga. */
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
- /** Fetch a studio by its AniList ID. */
1051
- getStudio(id: number): Promise<Studio>;
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
- /** Retrieve a cached value, or `undefined` if missing / expired. */
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 };