{"id":45191927,"url":"https://github.com/gonzyui/ani-client","last_synced_at":"2026-04-29T18:01:07.206Z","repository":{"id":339409639,"uuid":"1161802220","full_name":"gonzyui/ani-client","owner":"gonzyui","description":"A simple and typed client to fetch anime, manga, characters and user data from AniList","archived":false,"fork":false,"pushed_at":"2026-04-25T20:32:41.000Z","size":3313,"stargazers_count":5,"open_issues_count":1,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-25T21:25:53.302Z","etag":null,"topics":["anilist","anilist-api","anilist-client","anilist-library","anilistapi","anime","anime-api","anime-list","anime-search","api-client","graphql","manga","manga-api","mangadex","mangadex-api","mangas","nodejs","npm-package","typescript"],"latest_commit_sha":null,"homepage":"https://ani-client.js.org/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gonzyui.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-19T14:35:16.000Z","updated_at":"2026-04-25T20:32:46.000Z","dependencies_parsed_at":null,"dependency_job_id":"d6453024-215c-494d-afb9-7949eace139c","html_url":"https://github.com/gonzyui/ani-client","commit_stats":null,"previous_names":["gonzyui/ani-client"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/gonzyui/ani-client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzyui%2Fani-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzyui%2Fani-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzyui%2Fani-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzyui%2Fani-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gonzyui","download_url":"https://codeload.github.com/gonzyui/ani-client/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzyui%2Fani-client/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32437111,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T17:34:55.123Z","status":"ssl_error","status_checked_at":"2026-04-29T17:34:45.749Z","response_time":110,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anilist","anilist-api","anilist-client","anilist-library","anilistapi","anime","anime-api","anime-list","anime-search","api-client","graphql","manga","manga-api","mangadex","mangadex-api","mangas","nodejs","npm-package","typescript"],"created_at":"2026-02-20T12:07:14.229Z","updated_at":"2026-04-29T18:01:07.137Z","avatar_url":"https://github.com/gonzyui.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ani-client\n\n[![CI](https://github.com/gonzyui/ani-client/actions/workflows/ci.yml/badge.svg)](https://github.com/gonzyui/ani-client/actions/workflows/ci.yml)\n[![npm version](https://img.shields.io/npm/v/ani-client)](https://www.npmjs.com/package/ani-client)\n[![npm downloads](https://img.shields.io/npm/dm/ani-client)](https://www.npmjs.com/package/ani-client)\n[![codecov](https://codecov.io/gh/gonzyui/ani-client/graph/badge.svg)](https://codecov.io/gh/gonzyui/ani-client)\n[![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue)](https://www.typescriptlang.org/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n\n\u003e A fully typed, zero-dependency client for the [AniList](https://anilist.co) GraphQL API.\n\n✨ **Showcase**: [See who's using ani-client](https://ani-client.js.org/showcase)\n\n**Support server** [Discord server](https://discord.gg/3P7twDurUD)\n\n## Highlights\n\n- **Zero dependencies** — uses the native `fetch` API\n- **Universal** — Node.js ≥ 20, Bun, Deno, and modern browsers\n- **Dual format** — ships ESM + CJS with full `.d.ts` declarations\n- **LRU cache** with TTL, stale-while-revalidate, and hit/miss stats\n- **Rate-limit protection** with exponential backoff, retries, and custom strategies\n- **Request deduplication** — concurrent identical queries share a single in-flight request\n- **Batch queries** — fetch up to 50 media/characters/staff in one API call\n- **Auto-pagination** — async iterator that yields items across pages\n- **AbortSignal support** — cancel globally or per-request with `withSignal()`\n- **Injectable logger** — plug in `console`, pino, winston, or any compatible logger\n- **Redis-ready** — swap the cache adapter with the built-in `RedisCache` for distributed setups\n\n## Install\n\n```bash\nnpm install ani-client\n# or\npnpm add ani-client\n# or\nyarn add ani-client\n```\n\n## Quick start\n\n```ts\nimport { AniListClient, MediaType } from \"ani-client\";\n\nconst client = new AniListClient();\n\n// Fetch an anime by AniList ID\nconst bebop = await client.getMedia(1);\nconsole.log(bebop.title.romaji); // \"Cowboy Bebop\"\n\n// Search with filters\nconst results = await client.searchMedia({\n  query: \"Naruto\",\n  type: MediaType.ANIME,\n  genres: [\"Action\"],\n  perPage: 10,\n});\n\n// Cross-platform lookup by MyAnimeList ID\nconst fma = await client.getMediaByMalId(5114);\n```\n\n## Features at a glance\n\n### Caching \u0026 stale-while-revalidate\n\n```ts\nconst client = new AniListClient({\n  cache: {\n    ttl: 1000 * 60 * 5,               // 5 min TTL\n    maxSize: 200,                      // LRU capacity\n    staleWhileRevalidateMs: 60_000,    // serve stale for 1 min after expiry\n  },\n});\n\n// Check cache performance\nconsole.log(client.cacheStats);\n// { hits: 42, misses: 8, stales: 2, hitRate: 0.84 }\n```\n\n### Per-request cancellation\n\n```ts\nconst controller = new AbortController();\nconst scoped = client.withSignal(controller.signal);\n\nsetTimeout(() =\u003e controller.abort(), 3_000);\nconst anime = await scoped.getMedia(1);\n```\n\n### Structured logging\n\n```ts\nconst client = new AniListClient({ logger: console });\n// debug: \"API request\"  { query: \"query { Media(id: 1) { ... } }\" }\n// debug: \"Request complete\" { durationMs: 120, status: 200 }\n```\n\n### Rate limiting \u0026 retries\n\n```ts\nconst client = new AniListClient({\n  rateLimit: {\n    maxRequests: 85,\n    windowMs: 60_000,\n    maxRetries: 3,\n    retryOnNetworkError: true,\n    retryStrategy: (attempt) =\u003e (attempt + 1) * 1000, // linear backoff\n  },\n});\n\nconsole.log(client.rateLimitInfo);\n// { remaining: 82, limit: 85, reset: 1741104000 }\n```\n\n### Batch \u0026 pagination\n\n```ts\n// Fetch 100 anime in 2 API calls (50 per batch)\nconst batch = await client.getMediaBatch([1, 2, 3, /* ...up to 100 IDs */]);\n\n// Auto-paginate through all results\nfor await (const anime of client.paginate(\n  (page) =\u003e client.searchMedia({ query: \"Gundam\", page, perPage: 50 }),\n  5, // max 5 pages\n)) {\n  console.log(anime.title.romaji);\n}\n```\n\n### Users, characters, studios \u0026 more\n\n```ts\nconst user = await client.getUser(\"AniList\");\nconst favs = await client.getUserFavorites(\"AniList\", { perPage: 50 });\nconst char = await client.getCharacter(1, { voiceActors: true });\nconst studio = await client.getStudio(21, { media: { perPage: 50 } });\nconst schedule = await client.getWeeklySchedule();\n```\n\n## Documentation\n\nFull API reference, guides (caching, pagination, includes, hooks, etc.) and configuration examples:\n\n**[ani-client.js.org](https://ani-client.js.org)**\n\n## Requirements\n\n| Runtime | Version |\n| --- | --- |\n| Node.js | ≥ 20 |\n| Bun | ≥ 1.0 |\n| Deno | ≥ 1.28 |\n| Browsers | Any with `fetch` + `AbortController` |\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, coding standards, and PR guidelines.\n\n## License\n\n[MIT](LICENSE) © gonzyui\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgonzyui%2Fani-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgonzyui%2Fani-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgonzyui%2Fani-client/lists"}