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/dist/index.d.ts CHANGED
@@ -1,3 +1,320 @@
1
+ interface PageInfo {
2
+ total: number | null;
3
+ perPage: number | null;
4
+ currentPage: number | null;
5
+ lastPage: number | null;
6
+ hasNextPage: boolean | null;
7
+ }
8
+ interface PagedResult<T> {
9
+ pageInfo: PageInfo;
10
+ results: T[];
11
+ }
12
+ interface FuzzyDate {
13
+ year: number | null;
14
+ month: number | null;
15
+ day: number | null;
16
+ }
17
+ interface ExternalLink {
18
+ id: number;
19
+ url: string | null;
20
+ site: string;
21
+ type: string | null;
22
+ icon: string | null;
23
+ color: string | null;
24
+ }
25
+ /**
26
+ * Interface that all cache adapters must implement.
27
+ * Methods may return sync values or Promises — the client awaits all calls.
28
+ */
29
+ interface CacheAdapter {
30
+ /** Retrieve a cached value, or `undefined` if missing / expired. */
31
+ get<T>(key: string): T | undefined | Promise<T | undefined>;
32
+ /** Store a value in the cache. */
33
+ set<T>(key: string, data: T): void | Promise<void>;
34
+ /** Remove a specific entry. Returns `true` if the key existed. */
35
+ delete(key: string): boolean | Promise<boolean>;
36
+ /** Clear the entire cache. */
37
+ clear(): void | Promise<void>;
38
+ /** Number of entries currently stored. */
39
+ readonly size: number | Promise<number>;
40
+ /** Return all cache keys. */
41
+ keys(): string[] | Promise<string[]>;
42
+ /** Bulk-remove entries matching a pattern. Optional — the client provides a fallback. */
43
+ invalidate?(pattern: string | RegExp): number | Promise<number>;
44
+ }
45
+ /** Cache configuration options. */
46
+ interface CacheOptions {
47
+ /** Time-to-live in milliseconds (default: 86 400 000 = 24h) */
48
+ ttl?: number;
49
+ /** Maximum number of cached entries (default: 500, 0 = unlimited) */
50
+ maxSize?: number;
51
+ /** Set to false to disable caching entirely */
52
+ enabled?: boolean;
53
+ }
54
+ /** Rate limiter configuration options. */
55
+ interface RateLimitOptions {
56
+ /** Max requests per window (default: 85) */
57
+ maxRequests?: number;
58
+ /** Window size in ms (default: 60 000) */
59
+ windowMs?: number;
60
+ /** Max retries on 429 (default: 3) */
61
+ maxRetries?: number;
62
+ /** Retry delay in ms when Retry-After header is absent (default: 2000) */
63
+ retryDelayMs?: number;
64
+ /** Set to false to disable rate limiting entirely */
65
+ enabled?: boolean;
66
+ /** Timeout per request in ms (default: 30 000). 0 = no timeout. */
67
+ timeoutMs?: number;
68
+ /** Retry on network errors like ECONNRESET / ETIMEDOUT (default: true) */
69
+ retryOnNetworkError?: boolean;
70
+ }
71
+ /** Event hooks for logging, debugging, and monitoring. */
72
+ interface AniListHooks {
73
+ /** Called before every API request. */
74
+ onRequest?: (query: string, variables: Record<string, unknown>) => void;
75
+ /** Called when a response is served from cache. */
76
+ onCacheHit?: (key: string) => void;
77
+ /** Called when the rate limiter enforces a wait (429 received). */
78
+ onRateLimit?: (retryAfterMs: number) => void;
79
+ /** Called when a request is retried (429 or network error). */
80
+ onRetry?: (attempt: number, reason: string, delayMs: number) => void;
81
+ /** Called when a request completes. */
82
+ onResponse?: (query: string, durationMs: number, fromCache: boolean) => void;
83
+ }
84
+ interface AniListClientOptions {
85
+ /** Optional AniList OAuth token for authenticated requests */
86
+ token?: string;
87
+ /** Custom API endpoint (defaults to https://graphql.anilist.co) */
88
+ apiUrl?: string;
89
+ /** Cache configuration (enabled by default, 24h TTL) */
90
+ cache?: CacheOptions;
91
+ /** Custom cache adapter (e.g. RedisCache). Takes precedence over `cache`. */
92
+ cacheAdapter?: CacheAdapter;
93
+ /** Rate limiter configuration (enabled by default, 85 req/min) */
94
+ rateLimit?: RateLimitOptions;
95
+ /** Event hooks for logging, debugging, and monitoring */
96
+ hooks?: AniListHooks;
97
+ }
98
+
99
+ interface StaffName {
100
+ first: string | null;
101
+ middle: string | null;
102
+ last: string | null;
103
+ full: string | null;
104
+ native: string | null;
105
+ }
106
+ interface StaffImage {
107
+ large: string | null;
108
+ medium: string | null;
109
+ }
110
+ /** A media node returned inside `Staff.staffMedia`. */
111
+ interface StaffMediaNode {
112
+ id: number;
113
+ title: MediaTitle;
114
+ type: MediaType;
115
+ format: MediaFormat | null;
116
+ status: MediaStatus | null;
117
+ coverImage: MediaCoverImage;
118
+ bannerImage: string | null;
119
+ genres: string[];
120
+ averageScore: number | null;
121
+ meanScore: number | null;
122
+ popularity: number | null;
123
+ favourites: number | null;
124
+ episodes: number | null;
125
+ trending: number | null;
126
+ hashtag: string | null;
127
+ season: MediaSeason | null;
128
+ seasonYear: number | null;
129
+ startDate: FuzzyDate | null;
130
+ endDate: FuzzyDate | null;
131
+ nextAiringEpisode: {
132
+ id: number;
133
+ airingAt: number;
134
+ episode: number;
135
+ mediaId: number;
136
+ timeUntilAiring: number;
137
+ } | null;
138
+ studios: {
139
+ edges: {
140
+ node: {
141
+ name: string;
142
+ };
143
+ }[];
144
+ } | null;
145
+ siteUrl: string | null;
146
+ }
147
+ interface Staff {
148
+ id: number;
149
+ name: StaffName;
150
+ language: string | null;
151
+ image: StaffImage;
152
+ description: string | null;
153
+ primaryOccupations: string[];
154
+ gender: string | null;
155
+ dateOfBirth: FuzzyDate | null;
156
+ dateOfDeath: FuzzyDate | null;
157
+ age: string | null;
158
+ yearsActive: number[];
159
+ homeTown: string | null;
160
+ bloodType: string | null;
161
+ favourites: number | null;
162
+ siteUrl: string | null;
163
+ /** Media the staff member has worked on — only present when requested via include options. */
164
+ staffMedia?: {
165
+ nodes: StaffMediaNode[];
166
+ } | null;
167
+ }
168
+ /** Options to include additional related data when fetching a staff member by ID. */
169
+ interface StaffIncludeOptions {
170
+ /** Include media the staff member has worked on.
171
+ * `true` = 25 results sorted by popularity. Object form to customize. */
172
+ media?: boolean | {
173
+ perPage?: number;
174
+ sort?: boolean;
175
+ };
176
+ }
177
+ interface SearchStaffOptions {
178
+ query?: string;
179
+ sort?: CharacterSort[];
180
+ page?: number;
181
+ perPage?: number;
182
+ }
183
+ /** Compact voice actor data returned inside character edges. */
184
+ interface VoiceActor {
185
+ id: number;
186
+ name: {
187
+ first: string | null;
188
+ middle: string | null;
189
+ last: string | null;
190
+ full: string | null;
191
+ native: string | null;
192
+ userPreferred: string | null;
193
+ };
194
+ languageV2: string | null;
195
+ image: StaffImage;
196
+ gender: string | null;
197
+ primaryOccupations: string[];
198
+ siteUrl: string | null;
199
+ }
200
+
201
+ declare enum CharacterSort {
202
+ ID = "ID",
203
+ ID_DESC = "ID_DESC",
204
+ ROLE = "ROLE",
205
+ ROLE_DESC = "ROLE_DESC",
206
+ SEARCH_MATCH = "SEARCH_MATCH",
207
+ FAVOURITES = "FAVOURITES",
208
+ FAVOURITES_DESC = "FAVOURITES_DESC"
209
+ }
210
+ declare enum CharacterRole {
211
+ MAIN = "MAIN",
212
+ SUPPORTING = "SUPPORTING",
213
+ BACKGROUND = "BACKGROUND"
214
+ }
215
+ interface CharacterName {
216
+ first: string | null;
217
+ middle: string | null;
218
+ last: string | null;
219
+ full: string | null;
220
+ native: string | null;
221
+ alternative: string[];
222
+ }
223
+ interface CharacterImage {
224
+ large: string | null;
225
+ medium: string | null;
226
+ }
227
+ type CharacterMediaNode = Pick<Media, "id" | "title" | "type" | "coverImage" | "siteUrl">;
228
+ interface CharacterMediaEdge {
229
+ node: CharacterMediaNode;
230
+ voiceActors?: VoiceActor[];
231
+ }
232
+ interface Character {
233
+ id: number;
234
+ name: CharacterName;
235
+ image: CharacterImage;
236
+ description: string | null;
237
+ gender: string | null;
238
+ dateOfBirth: FuzzyDate | null;
239
+ age: string | null;
240
+ bloodType: string | null;
241
+ favourites: number | null;
242
+ siteUrl: string | null;
243
+ media: {
244
+ nodes?: CharacterMediaNode[];
245
+ edges?: CharacterMediaEdge[];
246
+ } | null;
247
+ }
248
+ /** Options for including extra data when fetching a character. */
249
+ interface CharacterIncludeOptions {
250
+ /** Include voice actors for each media the character appears in. */
251
+ voiceActors?: boolean;
252
+ }
253
+ interface SearchCharacterOptions {
254
+ query?: string;
255
+ sort?: CharacterSort[];
256
+ page?: number;
257
+ perPage?: number;
258
+ /** Include voice actors for each media the character appears in. */
259
+ voiceActors?: boolean;
260
+ }
261
+
262
+ interface Studio {
263
+ id: number;
264
+ name: string;
265
+ isAnimationStudio: boolean;
266
+ siteUrl: string | null;
267
+ }
268
+ interface StudioConnection {
269
+ nodes: Studio[];
270
+ }
271
+ interface StudioDetail {
272
+ id: number;
273
+ name: string;
274
+ isAnimationStudio: boolean;
275
+ siteUrl: string | null;
276
+ favourites: number | null;
277
+ media: {
278
+ pageInfo: PageInfo;
279
+ nodes: Pick<Media, "id" | "title" | "type" | "format" | "coverImage" | "siteUrl">[];
280
+ } | null;
281
+ }
282
+ interface SearchStudioOptions {
283
+ query?: string;
284
+ page?: number;
285
+ perPage?: number;
286
+ }
287
+
288
+ interface UserAvatar {
289
+ large: string | null;
290
+ medium: string | null;
291
+ }
292
+ interface UserStatistics {
293
+ count: number;
294
+ meanScore: number;
295
+ minutesWatched: number;
296
+ episodesWatched: number;
297
+ chaptersRead: number;
298
+ volumesRead: number;
299
+ }
300
+ interface User {
301
+ id: number;
302
+ name: string;
303
+ about: string | null;
304
+ avatar: UserAvatar;
305
+ bannerImage: string | null;
306
+ isFollowing: boolean | null;
307
+ isFollower: boolean | null;
308
+ donatorTier: number | null;
309
+ donatorBadge: string | null;
310
+ createdAt: number | null;
311
+ siteUrl: string | null;
312
+ statistics: {
313
+ anime: UserStatistics;
314
+ manga: UserStatistics;
315
+ } | null;
316
+ }
317
+
1
318
  declare enum MediaType {
2
319
  ANIME = "ANIME",
3
320
  MANGA = "MANGA"
@@ -72,20 +389,6 @@ declare enum AiringSort {
72
389
  EPISODE = "EPISODE",
73
390
  EPISODE_DESC = "EPISODE_DESC"
74
391
  }
75
- declare enum CharacterSort {
76
- ID = "ID",
77
- ID_DESC = "ID_DESC",
78
- ROLE = "ROLE",
79
- ROLE_DESC = "ROLE_DESC",
80
- SEARCH_MATCH = "SEARCH_MATCH",
81
- FAVOURITES = "FAVOURITES",
82
- FAVOURITES_DESC = "FAVOURITES_DESC"
83
- }
84
- declare enum CharacterRole {
85
- MAIN = "MAIN",
86
- SUPPORTING = "SUPPORTING",
87
- BACKGROUND = "BACKGROUND"
88
- }
89
392
  interface MediaTitle {
90
393
  romaji: string | null;
91
394
  english: string | null;
@@ -98,11 +401,6 @@ interface MediaCoverImage {
98
401
  medium: string | null;
99
402
  color: string | null;
100
403
  }
101
- interface FuzzyDate {
102
- year: number | null;
103
- month: number | null;
104
- day: number | null;
105
- }
106
404
  interface MediaTrailer {
107
405
  id: string | null;
108
406
  site: string | null;
@@ -116,15 +414,6 @@ interface MediaTag {
116
414
  rank: number | null;
117
415
  isMediaSpoiler: boolean | null;
118
416
  }
119
- interface Studio {
120
- id: number;
121
- name: string;
122
- isAnimationStudio: boolean;
123
- siteUrl: string | null;
124
- }
125
- interface StudioConnection {
126
- nodes: Studio[];
127
- }
128
417
  declare enum MediaRelationType {
129
418
  ADAPTATION = "ADAPTATION",
130
419
  PREQUEL = "PREQUEL",
@@ -147,35 +436,6 @@ interface MediaEdge {
147
436
  interface MediaConnection {
148
437
  edges: MediaEdge[];
149
438
  }
150
- interface CharacterName {
151
- first: string | null;
152
- middle: string | null;
153
- last: string | null;
154
- full: string | null;
155
- native: string | null;
156
- alternative: string[];
157
- }
158
- interface CharacterImage {
159
- large: string | null;
160
- medium: string | null;
161
- }
162
- /** Compact voice actor data returned inside character edges. */
163
- interface VoiceActor {
164
- id: number;
165
- name: {
166
- first: string | null;
167
- middle: string | null;
168
- last: string | null;
169
- full: string | null;
170
- native: string | null;
171
- userPreferred: string | null;
172
- };
173
- languageV2: string | null;
174
- image: StaffImage;
175
- gender: string | null;
176
- primaryOccupations: string[];
177
- siteUrl: string | null;
178
- }
179
439
  interface MediaCharacterEdge {
180
440
  role: CharacterRole;
181
441
  node: Omit<Character, "media">;
@@ -197,20 +457,12 @@ interface StreamingEpisode {
197
457
  url: string | null;
198
458
  site: string | null;
199
459
  }
200
- interface ExternalLink {
201
- id: number;
202
- url: string | null;
203
- site: string;
204
- type: string | null;
205
- icon: string | null;
206
- color: string | null;
207
- }
208
460
  interface ScoreDistribution {
209
461
  score: number;
210
462
  amount: number;
211
463
  }
212
464
  interface StatusDistribution {
213
- status: MediaListStatus | string;
465
+ status: string;
214
466
  amount: number;
215
467
  }
216
468
  interface MediaStats {
@@ -237,132 +489,34 @@ interface Media {
237
489
  episodes: number | null;
238
490
  duration: number | null;
239
491
  chapters: number | null;
240
- volumes: number | null;
241
- countryOfOrigin: string | null;
242
- isLicensed: boolean | null;
243
- source: string | null;
244
- hashtag: string | null;
245
- trailer: MediaTrailer | null;
246
- coverImage: MediaCoverImage;
247
- bannerImage: string | null;
248
- genres: string[];
249
- synonyms: string[];
250
- averageScore: number | null;
251
- meanScore: number | null;
252
- popularity: number | null;
253
- favourites: number | null;
254
- trending: number | null;
255
- tags: MediaTag[];
256
- studios: StudioConnection;
257
- relations: MediaConnection | null;
258
- characters?: MediaCharacterConnection;
259
- staff?: MediaStaffConnection;
260
- streamingEpisodes?: StreamingEpisode[];
261
- externalLinks?: ExternalLink[];
262
- stats?: MediaStats;
263
- recommendations?: {
264
- nodes: MediaRecommendationNode[];
265
- };
266
- isAdult: boolean | null;
267
- siteUrl: string | null;
268
- }
269
- type CharacterMediaNode = Pick<Media, "id" | "title" | "type" | "coverImage" | "siteUrl">;
270
- interface CharacterMediaEdge {
271
- node: CharacterMediaNode;
272
- voiceActors?: VoiceActor[];
273
- }
274
- interface Character {
275
- id: number;
276
- name: CharacterName;
277
- image: CharacterImage;
278
- description: string | null;
279
- gender: string | null;
280
- dateOfBirth: FuzzyDate | null;
281
- age: string | null;
282
- bloodType: string | null;
283
- favourites: number | null;
284
- siteUrl: string | null;
285
- media: {
286
- nodes?: CharacterMediaNode[];
287
- edges?: CharacterMediaEdge[];
288
- } | null;
289
- }
290
- /** Options for including extra data when fetching a character. */
291
- interface CharacterIncludeOptions {
292
- /** Include voice actors for each media the character appears in. */
293
- voiceActors?: boolean;
294
- }
295
- interface StaffName {
296
- first: string | null;
297
- middle: string | null;
298
- last: string | null;
299
- full: string | null;
300
- native: string | null;
301
- }
302
- interface StaffImage {
303
- large: string | null;
304
- medium: string | null;
305
- }
306
- interface Staff {
307
- id: number;
308
- name: StaffName;
309
- language: string | null;
310
- image: StaffImage;
311
- description: string | null;
312
- primaryOccupations: string[];
313
- gender: string | null;
314
- dateOfBirth: FuzzyDate | null;
315
- dateOfDeath: FuzzyDate | null;
316
- age: string | null;
317
- yearsActive: number[];
318
- homeTown: string | null;
319
- bloodType: string | null;
320
- favourites: number | null;
321
- siteUrl: string | null;
322
- }
323
- interface UserAvatar {
324
- large: string | null;
325
- medium: string | null;
326
- }
327
- interface UserStatistics {
328
- count: number;
329
- meanScore: number;
330
- minutesWatched: number;
331
- episodesWatched: number;
332
- chaptersRead: number;
333
- volumesRead: number;
334
- }
335
- interface User {
336
- id: number;
337
- name: string;
338
- about: string | null;
339
- avatar: UserAvatar;
492
+ volumes: number | null;
493
+ countryOfOrigin: string | null;
494
+ isLicensed: boolean | null;
495
+ source: string | null;
496
+ hashtag: string | null;
497
+ trailer: MediaTrailer | null;
498
+ coverImage: MediaCoverImage;
340
499
  bannerImage: string | null;
341
- isFollowing: boolean | null;
342
- isFollower: boolean | null;
343
- donatorTier: number | null;
344
- donatorBadge: string | null;
345
- createdAt: number | null;
500
+ genres: string[];
501
+ synonyms: string[];
502
+ averageScore: number | null;
503
+ meanScore: number | null;
504
+ popularity: number | null;
505
+ favourites: number | null;
506
+ trending: number | null;
507
+ tags: MediaTag[];
508
+ studios: StudioConnection;
509
+ relations: MediaConnection | null;
510
+ characters?: MediaCharacterConnection;
511
+ staff?: MediaStaffConnection;
512
+ streamingEpisodes?: StreamingEpisode[];
513
+ externalLinks?: ExternalLink[];
514
+ stats?: MediaStats;
515
+ recommendations?: {
516
+ nodes: MediaRecommendationNode[];
517
+ };
518
+ isAdult: boolean | null;
346
519
  siteUrl: string | null;
347
- statistics: {
348
- anime: UserStatistics;
349
- manga: UserStatistics;
350
- } | null;
351
- }
352
- interface AiringSchedule {
353
- id: number;
354
- airingAt: number;
355
- timeUntilAiring: number;
356
- episode: number;
357
- mediaId: number;
358
- media: Media;
359
- }
360
- interface PageInfo {
361
- total: number | null;
362
- perPage: number | null;
363
- currentPage: number | null;
364
- lastPage: number | null;
365
- hasNextPage: boolean | null;
366
520
  }
367
521
  interface SearchMediaOptions {
368
522
  query?: string;
@@ -378,24 +532,6 @@ interface SearchMediaOptions {
378
532
  page?: number;
379
533
  perPage?: number;
380
534
  }
381
- interface SearchCharacterOptions {
382
- query?: string;
383
- sort?: CharacterSort[];
384
- page?: number;
385
- perPage?: number;
386
- /** Include voice actors for each media the character appears in. */
387
- voiceActors?: boolean;
388
- }
389
- interface SearchStaffOptions {
390
- query?: string;
391
- sort?: CharacterSort[];
392
- page?: number;
393
- perPage?: number;
394
- }
395
- interface PagedResult<T> {
396
- pageInfo: PageInfo;
397
- results: T[];
398
- }
399
535
  interface GetAiringOptions {
400
536
  /** Only show episodes that aired after this UNIX timestamp */
401
537
  airingAtGreater?: number;
@@ -445,6 +581,58 @@ interface GetRecommendationsOptions {
445
581
  page?: number;
446
582
  perPage?: number;
447
583
  }
584
+ interface GetSeasonOptions {
585
+ /** The season (WINTER, SPRING, SUMMER, FALL) */
586
+ season: MediaSeason;
587
+ /** The year */
588
+ seasonYear: number;
589
+ /** Filter by ANIME or MANGA (defaults to ANIME) */
590
+ type?: MediaType;
591
+ /** Sort order (default: POPULARITY_DESC) */
592
+ sort?: MediaSort[];
593
+ page?: number;
594
+ perPage?: number;
595
+ }
596
+ /**
597
+ * Options to include additional related data when fetching a media entry.
598
+ * Pass `true` to include with defaults, or an object to customize.
599
+ */
600
+ interface MediaIncludeOptions {
601
+ /** Include characters with their roles (MAIN, SUPPORTING, BACKGROUND).
602
+ * `true` = 25 results sorted by role. Object form to customize. */
603
+ characters?: boolean | {
604
+ perPage?: number;
605
+ sort?: boolean;
606
+ voiceActors?: boolean;
607
+ };
608
+ /** Include staff members with their roles.
609
+ * `true` = 25 results sorted by relevance. Object form to customize. */
610
+ staff?: boolean | {
611
+ perPage?: number;
612
+ sort?: boolean;
613
+ };
614
+ /** Include relations (default: `true` for backward compat). Set to `false` to exclude. */
615
+ relations?: boolean;
616
+ /** Include streaming episode links (Crunchyroll, Funimation, etc.) */
617
+ streamingEpisodes?: boolean;
618
+ /** Include external links (MAL, official site, etc.) */
619
+ externalLinks?: boolean;
620
+ /** Include score & status distribution stats */
621
+ stats?: boolean;
622
+ /** Include user recommendations. `true` = 10 results, or customize with `{ perPage }`. */
623
+ recommendations?: boolean | {
624
+ perPage?: number;
625
+ };
626
+ }
627
+ interface AiringSchedule {
628
+ id: number;
629
+ airingAt: number;
630
+ timeUntilAiring: number;
631
+ episode: number;
632
+ mediaId: number;
633
+ media: Media;
634
+ }
635
+
448
636
  declare enum MediaListStatus {
449
637
  CURRENT = "CURRENT",
450
638
  PLANNING = "PLANNING",
@@ -502,18 +690,6 @@ interface MediaListEntry {
502
690
  createdAt: number | null;
503
691
  media: Media;
504
692
  }
505
- interface GetSeasonOptions {
506
- /** The season (WINTER, SPRING, SUMMER, FALL) */
507
- season: MediaSeason;
508
- /** The year */
509
- seasonYear: number;
510
- /** Filter by ANIME or MANGA (defaults to ANIME) */
511
- type?: MediaType;
512
- /** Sort order (default: POPULARITY_DESC) */
513
- sort?: MediaSort[];
514
- page?: number;
515
- perPage?: number;
516
- }
517
693
  interface GetUserMediaListOptions {
518
694
  /** User ID (provide either userId or userName) */
519
695
  userId?: number;
@@ -528,126 +704,6 @@ interface GetUserMediaListOptions {
528
704
  page?: number;
529
705
  perPage?: number;
530
706
  }
531
- interface StudioDetail {
532
- id: number;
533
- name: string;
534
- isAnimationStudio: boolean;
535
- siteUrl: string | null;
536
- favourites: number | null;
537
- media: {
538
- pageInfo: PageInfo;
539
- nodes: Pick<Media, "id" | "title" | "type" | "format" | "coverImage" | "siteUrl">[];
540
- } | null;
541
- }
542
- interface SearchStudioOptions {
543
- query?: string;
544
- page?: number;
545
- perPage?: number;
546
- }
547
- /**
548
- * Options to include additional related data when fetching a media entry.
549
- * Pass `true` to include with defaults, or an object to customize.
550
- */
551
- interface MediaIncludeOptions {
552
- /** Include characters with their roles (MAIN, SUPPORTING, BACKGROUND).
553
- * `true` = 25 results sorted by role. Object form to customize. */
554
- characters?: boolean | {
555
- perPage?: number;
556
- sort?: boolean;
557
- voiceActors?: boolean;
558
- };
559
- /** Include staff members with their roles.
560
- * `true` = 25 results sorted by relevance. Object form to customize. */
561
- staff?: boolean | {
562
- perPage?: number;
563
- sort?: boolean;
564
- };
565
- /** Include relations (default: `true` for backward compat). Set to `false` to exclude. */
566
- relations?: boolean;
567
- /** Include streaming episode links (Crunchyroll, Funimation, etc.) */
568
- streamingEpisodes?: boolean;
569
- /** Include external links (MAL, official site, etc.) */
570
- externalLinks?: boolean;
571
- /** Include score & status distribution stats */
572
- stats?: boolean;
573
- /** Include user recommendations. `true` = 10 results, or customize with `{ perPage }`. */
574
- recommendations?: boolean | {
575
- perPage?: number;
576
- };
577
- }
578
- /**
579
- * Interface that all cache adapters must implement.
580
- * Methods may return sync values or Promises — the client awaits all calls.
581
- */
582
- interface CacheAdapter {
583
- /** Retrieve a cached value, or `undefined` if missing / expired. */
584
- get<T>(key: string): T | undefined | Promise<T | undefined>;
585
- /** Store a value in the cache. */
586
- set<T>(key: string, data: T): void | Promise<void>;
587
- /** Remove a specific entry. Returns `true` if the key existed. */
588
- delete(key: string): boolean | Promise<boolean>;
589
- /** Clear the entire cache. */
590
- clear(): void | Promise<void>;
591
- /** Number of entries currently stored (sync). Returns -1 if unknown. */
592
- readonly size: number;
593
- /** Return all cache keys. */
594
- keys(): string[] | Promise<string[]>;
595
- /** Bulk-remove entries matching a pattern. Optional — the client provides a fallback. */
596
- invalidate?(pattern: string | RegExp): number | Promise<number>;
597
- }
598
- /** Cache configuration options. */
599
- interface CacheOptions {
600
- /** Time-to-live in milliseconds (default: 86 400 000 = 24h) */
601
- ttl?: number;
602
- /** Maximum number of cached entries (default: 500, 0 = unlimited) */
603
- maxSize?: number;
604
- /** Set to false to disable caching entirely */
605
- enabled?: boolean;
606
- }
607
- /** Rate limiter configuration options. */
608
- interface RateLimitOptions {
609
- /** Max requests per window (default: 85) */
610
- maxRequests?: number;
611
- /** Window size in ms (default: 60 000) */
612
- windowMs?: number;
613
- /** Max retries on 429 (default: 3) */
614
- maxRetries?: number;
615
- /** Retry delay in ms when Retry-After header is absent (default: 2000) */
616
- retryDelayMs?: number;
617
- /** Set to false to disable rate limiting entirely */
618
- enabled?: boolean;
619
- /** Timeout per request in ms (default: 30 000). 0 = no timeout. */
620
- timeoutMs?: number;
621
- /** Retry on network errors like ECONNRESET / ETIMEDOUT (default: true) */
622
- retryOnNetworkError?: boolean;
623
- }
624
- /** Event hooks for logging, debugging, and monitoring. */
625
- interface AniListHooks {
626
- /** Called before every API request. */
627
- onRequest?: (query: string, variables: Record<string, unknown>) => void;
628
- /** Called when a response is served from cache. */
629
- onCacheHit?: (key: string) => void;
630
- /** Called when the rate limiter enforces a wait (429 received). */
631
- onRateLimit?: (retryAfterMs: number) => void;
632
- /** Called when a request is retried (429 or network error). */
633
- onRetry?: (attempt: number, reason: string, delayMs: number) => void;
634
- /** Called when a request completes. */
635
- onResponse?: (query: string, durationMs: number, fromCache: boolean) => void;
636
- }
637
- interface AniListClientOptions {
638
- /** Optional AniList OAuth token for authenticated requests */
639
- token?: string;
640
- /** Custom API endpoint (defaults to https://graphql.anilist.co) */
641
- apiUrl?: string;
642
- /** Cache configuration (enabled by default, 24h TTL) */
643
- cache?: CacheOptions;
644
- /** Custom cache adapter (e.g. RedisCache). Takes precedence over `cache`. */
645
- cacheAdapter?: CacheAdapter;
646
- /** Rate limiter configuration (enabled by default, 85 req/min) */
647
- rateLimit?: RateLimitOptions;
648
- /** Event hooks for logging, debugging, and monitoring */
649
- hooks?: AniListHooks;
650
- }
651
707
 
652
708
  /**
653
709
  * Lightweight AniList GraphQL client with built-in caching and rate limiting.
@@ -686,11 +742,6 @@ declare class AniListClient {
686
742
  * Shorthand for paginated queries that follow the `Page { pageInfo, <field>[] }` pattern.
687
743
  */
688
744
  private pagedRequest;
689
- /**
690
- * @internal
691
- * Clamp perPage to AniList's maximum of 50.
692
- */
693
- private clampPerPage;
694
745
  /**
695
746
  * Fetch a single media entry by its AniList ID.
696
747
  *
@@ -791,15 +842,20 @@ declare class AniListClient {
791
842
  * Fetch a staff member by AniList ID.
792
843
  *
793
844
  * @param id - The AniList staff ID
845
+ * @param include - Optional include options to fetch related data (e.g. media)
794
846
  * @returns The staff object
795
847
  *
796
848
  * @example
797
849
  * ```ts
798
850
  * const staff = await client.getStaff(95001);
799
851
  * console.log(staff.name.full);
852
+ *
853
+ * // With media the staff worked on
854
+ * const staff = await client.getStaff(95001, { media: true });
855
+ * staff.staffMedia?.nodes.forEach((m) => console.log(m.title.romaji));
800
856
  * ```
801
857
  */
802
- getStaff(id: number): Promise<Staff>;
858
+ getStaff(id: number, include?: StaffIncludeOptions): Promise<Staff>;
803
859
  /**
804
860
  * Search for staff (voice actors, directors, etc.).
805
861
  *
@@ -1040,17 +1096,15 @@ declare class AniListClient {
1040
1096
  getStaffBatch(ids: number[]): Promise<Staff[]>;
1041
1097
  /** @internal */
1042
1098
  private executeBatch;
1043
- /** @internal */
1044
- private chunk;
1045
1099
  /**
1046
1100
  * Clear the entire response cache.
1047
1101
  */
1048
1102
  clearCache(): Promise<void>;
1049
1103
  /**
1050
- * Number of entries currently in the cache (sync).
1051
- * For async adapters like Redis, this may be approximate.
1104
+ * Number of entries currently in the cache.
1105
+ * For async adapters like Redis, this may return a Promise.
1052
1106
  */
1053
- get cacheSize(): number;
1107
+ get cacheSize(): number | Promise<number>;
1054
1108
  /**
1055
1109
  * Remove cache entries whose key matches the given pattern.
1056
1110
  *
@@ -1088,7 +1142,7 @@ declare class MemoryCache implements CacheAdapter {
1088
1142
  /** Clear the entire cache. */
1089
1143
  clear(): void;
1090
1144
  /** Number of entries currently stored. */
1091
- get size(): number;
1145
+ get size(): number | Promise<number>;
1092
1146
  /** Return all cache keys. */
1093
1147
  keys(): string[];
1094
1148
  /**
@@ -1156,12 +1210,11 @@ declare class RedisCache implements CacheAdapter {
1156
1210
  private collectKeys;
1157
1211
  clear(): Promise<void>;
1158
1212
  /**
1159
- * Returns -1 because Redis keys can expire silently via TTL.
1160
- * Use `getSize()` for an accurate count.
1213
+ * Get the actual number of keys with this prefix in Redis.
1161
1214
  */
1162
- get size(): number;
1163
- /** Get the actual number of keys with this prefix in Redis. */
1164
- getSize(): Promise<number>;
1215
+ get size(): Promise<number>;
1216
+ /** @internal */
1217
+ private getSize;
1165
1218
  keys(): Promise<string[]>;
1166
1219
  /**
1167
1220
  * Remove all entries whose key matches the given glob pattern.
@@ -1207,4 +1260,4 @@ declare class RateLimiter {
1207
1260
  private sleep;
1208
1261
  }
1209
1262
 
1210
- 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 ExternalLink, 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, type MediaStaffConnection, type MediaStaffEdge, type MediaStats, MediaStatus, type MediaTag, type MediaTitle, type MediaTrailer, MediaType, MemoryCache, type PageInfo, type PagedResult, type RateLimitOptions, RateLimiter, type Recommendation, RecommendationSort, RedisCache, type RedisCacheOptions, type RedisLikeClient, type ScoreDistribution, type SearchCharacterOptions, type SearchMediaOptions, type SearchStaffOptions, type SearchStudioOptions, type Staff, type StaffImage, type StaffName, type StatusDistribution, type StreamingEpisode, type Studio, type StudioConnection, type StudioDetail, type User, type UserAvatar, type UserStatistics, type VoiceActor };
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 ExternalLink, 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, type MediaStaffConnection, type MediaStaffEdge, type MediaStats, MediaStatus, type MediaTag, type MediaTitle, type MediaTrailer, MediaType, MemoryCache, type PageInfo, type PagedResult, type RateLimitOptions, RateLimiter, type Recommendation, RecommendationSort, RedisCache, type RedisCacheOptions, type RedisLikeClient, type ScoreDistribution, type SearchCharacterOptions, type SearchMediaOptions, type SearchStaffOptions, type SearchStudioOptions, type Staff, type StaffImage, type StaffIncludeOptions, type StaffMediaNode, type StaffName, type StatusDistribution, type StreamingEpisode, type Studio, type StudioConnection, type StudioDetail, type User, type UserAvatar, type UserStatistics, type VoiceActor };