ani-client 1.3.0 → 1.4.1

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
@@ -7,7 +7,7 @@
7
7
  > A simple, typed client to fetch anime, manga, character, staff and user data from [AniList](https://anilist.co).
8
8
 
9
9
  - **Zero dependencies** — uses the native `fetch` API
10
- - **Universal** — Node.js ≥ 18, Bun, Deno and modern browsers
10
+ - **Universal** — Node.js ≥ 20, Bun, Deno and modern browsers
11
11
  - **Dual format** — ships ESM + CJS with full TypeScript declarations
12
12
  - **Built-in caching** — in-memory LRU with optional Redis adapter
13
13
  - **Rate-limit aware** — auto-retry on 429, configurable timeout & network error retry
@@ -22,6 +22,7 @@
22
22
  - [Client options](#client-options)
23
23
  - [API reference](#api-reference)
24
24
  - [Media](#media)
25
+ - [Include options](#include-options)
25
26
  - [Characters](#characters)
26
27
  - [Staff](#staff)
27
28
  - [Users](#users)
@@ -145,15 +146,27 @@ const client = new AniListClient({
145
146
 
146
147
  | Method | Description |
147
148
  | --- | --- |
148
- | `getMedia(id)` | Fetch a single anime / manga by ID |
149
+ | `getMedia(id, include?)` | Fetch a single anime / manga by ID with optional extra data |
149
150
  | `searchMedia(options?)` | Search & filter anime / manga |
150
151
  | `getTrending(type?, page?, perPage?)` | Currently trending entries |
151
152
  | `getMediaBySeason(options)` | Anime/manga for a given season & year |
152
153
  | `getRecommendations(mediaId, options?)` | User recommendations for a media |
153
154
 
154
155
  ```ts
156
+ // Simple — same as before
155
157
  const anime = await client.getMedia(1);
156
158
 
159
+ // With extra data
160
+ const anime = await client.getMedia(1, {
161
+ characters: { perPage: 25, sort: true },
162
+ staff: true,
163
+ relations: true,
164
+ streamingEpisodes: true,
165
+ externalLinks: true,
166
+ stats: true,
167
+ recommendations: { perPage: 5 },
168
+ });
169
+
157
170
  const results = await client.searchMedia({
158
171
  query: "Naruto",
159
172
  type: MediaType.ANIME,
@@ -163,16 +176,89 @@ const results = await client.searchMedia({
163
176
  });
164
177
  ```
165
178
 
179
+ ### Include options
180
+
181
+ The second parameter of `getMedia()` lets you opt-in to additional data. By default, only `relations` are included for backward compatibility.
182
+
183
+ | Option | Type | Default | Description |
184
+ | --- | --- | --- | --- |
185
+ | `characters` | `boolean \| { perPage?, sort?, voiceActors? }` | — | Characters with their roles (MAIN, SUPPORTING, BACKGROUND). Set `voiceActors: true` to include VA data. |
186
+ | `staff` | `boolean \| { perPage?, sort? }` | — | Staff members with their roles |
187
+ | `relations` | `boolean` | `true` | Sequels, prequels, adaptations, etc. Set `false` to exclude |
188
+ | `streamingEpisodes` | `boolean` | — | Streaming links (Crunchyroll, Funimation, etc.) |
189
+ | `externalLinks` | `boolean` | — | External links (MAL, official site, etc.) |
190
+ | `stats` | `boolean` | — | Score & status distribution |
191
+ | `recommendations` | `boolean \| { perPage? }` | — | User recommendations |
192
+
193
+ ```ts
194
+ // Include characters sorted by role (25 per page by default)
195
+ const anime = await client.getMedia(1, { characters: true });
196
+ anime.characters?.edges.forEach((e) =>
197
+ console.log(`${e.node.name.full} (${e.role})`)
198
+ );
199
+
200
+ // 50 characters, no sorting
201
+ const anime = await client.getMedia(1, {
202
+ characters: { perPage: 50, sort: false },
203
+ });
204
+
205
+ // Include voice actors alongside characters
206
+ const anime = await client.getMedia(1, {
207
+ characters: { voiceActors: true },
208
+ });
209
+ anime.characters?.edges.forEach((e) => {
210
+ console.log(e.node.name.full);
211
+ e.voiceActors?.forEach((va) =>
212
+ console.log(` VA: ${va.name.full} (${va.languageV2})`)
213
+ );
214
+ });
215
+
216
+ // Staff members
217
+ const anime = await client.getMedia(1, { staff: true });
218
+ anime.staff?.edges.forEach((e) =>
219
+ console.log(`${e.node.name.full} — ${e.role}`)
220
+ );
221
+
222
+ // Everything at once
223
+ const anime = await client.getMedia(1, {
224
+ characters: { perPage: 50 },
225
+ staff: { perPage: 25 },
226
+ relations: true,
227
+ streamingEpisodes: true,
228
+ externalLinks: true,
229
+ stats: true,
230
+ recommendations: { perPage: 10 },
231
+ });
232
+
233
+ // Lightweight — exclude relations
234
+ const anime = await client.getMedia(1, {
235
+ characters: true,
236
+ relations: false,
237
+ });
238
+ ```
239
+
166
240
  ### Characters
167
241
 
168
242
  | Method | Description |
169
243
  | --- | --- |
170
- | `getCharacter(id)` | Fetch a character by ID |
171
- | `searchCharacters(options?)` | Search characters by name |
244
+ | `getCharacter(id, include?)` | Fetch a character by ID, optionally with voice actors |
245
+ | `searchCharacters(options?)` | Search characters by name, optionally with voice actors |
172
246
 
173
247
  ```ts
174
248
  const spike = await client.getCharacter(1);
175
249
  const results = await client.searchCharacters({ query: "Luffy", perPage: 5 });
250
+
251
+ // With voice actors
252
+ const spike = await client.getCharacter(1, { voiceActors: true });
253
+ spike.media?.edges?.forEach((e) => {
254
+ console.log(e.node.title.romaji);
255
+ e.voiceActors?.forEach((va) =>
256
+ console.log(` VA: ${va.name.full} (${va.languageV2})`)
257
+ );
258
+ });
259
+
260
+ // Search with voice actors
261
+ const result = await client.searchCharacters({ query: "Luffy", voiceActors: true });
176
262
  ```
177
263
 
178
264
  ### Staff
@@ -266,13 +352,16 @@ recs.results.forEach((r) =>
266
352
 
267
353
  ### Relations
268
354
 
269
- Every media object includes a `relations` field with sequels, prequels, spin-offs, etc.
355
+ Relations (sequels, prequels, spin-offs, etc.) are included by default when using `getMedia()`. You can also explicitly request them via the `include` parameter, or exclude them with `relations: false`.
270
356
 
271
357
  ```ts
272
358
  const anime = await client.getMedia(1);
273
359
  anime.relations?.edges.forEach((edge) =>
274
360
  console.log(`${edge.relationType}: ${edge.node.title.romaji}`)
275
361
  );
362
+
363
+ // Exclude relations for a lighter response
364
+ const anime = await client.getMedia(1, { relations: false });
276
365
  ```
277
366
 
278
367
  Available types: `ADAPTATION`, `PREQUEL`, `SEQUEL`, `PARENT`, `SIDE_STORY`, `CHARACTER`, `SUMMARY`, `ALTERNATIVE`, `SPIN_OFF`, `OTHER`, `SOURCE`, `COMPILATION`, `CONTAINS`.
@@ -472,9 +561,13 @@ All types and enums are exported:
472
561
 
473
562
  ```ts
474
563
  import type {
475
- Media, Character, Staff, User,
564
+ Media, Character, Staff, User, VoiceActor,
476
565
  AiringSchedule, MediaListEntry, Recommendation, StudioDetail,
477
- MediaEdge, MediaConnection, PageInfo, PagedResult,
566
+ MediaEdge, MediaConnection, MediaCharacterEdge, MediaCharacterConnection,
567
+ CharacterMediaEdge, CharacterIncludeOptions,
568
+ MediaStaffEdge, MediaStaffConnection, MediaIncludeOptions,
569
+ StreamingEpisode, ExternalLink, MediaStats, MediaRecommendationNode,
570
+ PageInfo, PagedResult,
478
571
  CacheAdapter, AniListHooks, AniListClientOptions,
479
572
  SearchMediaOptions, SearchCharacterOptions, SearchStaffOptions,
480
573
  SearchStudioOptions, GetAiringOptions, GetRecentChaptersOptions,
@@ -484,7 +577,7 @@ import type {
484
577
 
485
578
  import {
486
579
  MediaType, MediaFormat, MediaStatus, MediaSeason, MediaSort,
487
- CharacterSort, AiringSort, RecommendationSort,
580
+ CharacterSort, CharacterRole, AiringSort, RecommendationSort,
488
581
  MediaRelationType, MediaListStatus, MediaListSort,
489
582
  } from "ani-client";
490
583
  ```