ani-client 2.2.0 → 2.2.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
@@ -10,8 +10,6 @@
10
10
  > A fully typed, zero-dependency client for the [AniList](https://anilist.co) GraphQL API.
11
11
  > Supports Node.js, Bun, Deno, and modern browsers.
12
12
 
13
- > 📌 **Note** – thanks for **1K+ downloads** this month on `npm` 🎉
14
-
15
13
  ## Features
16
14
 
17
15
  - **Zero dependencies** — uses the native `fetch` API
@@ -73,9 +71,6 @@ const client = new AniListClient({
73
71
  staleWhileRevalidateMs: 60_000, // serve stale for 1 min after expiry
74
72
  },
75
73
  });
76
-
77
- console.log(client.cacheStats);
78
- // { hits: 42, misses: 8, stales: 2, hitRate: 0.84 }
79
74
  ```
80
75
 
81
76
  For distributed setups, swap to the built-in Redis adapter:
@@ -220,7 +215,7 @@ const client = new AniListClient({
220
215
 
221
216
  | Runtime | Version |
222
217
  |----------|--------------------|
223
- | Node.js | ≥ 20 |
218
+ | Node.js | ≥ 22.13.0 |
224
219
  | Bun | ≥ 1.0 |
225
220
  | Deno | ≥ 1.28 |
226
221
  | Browsers | `fetch` + `AbortController` required |
@@ -246,6 +241,26 @@ Before opening an issue or a pull request, please read:
246
241
 
247
242
  This repository also includes GitHub issue templates and a pull request template to help keep reports and contributions consistent.
248
243
 
244
+ ## Development
245
+
246
+ Quick commands for local development and CI checks:
247
+
248
+ ```bash
249
+ pnpm install
250
+ pnpm run build # build dist
251
+ pnpm run typecheck # TypeScript strict checks
252
+ pnpm run lint # lint the codebase
253
+ pnpm test # run unit + integration tests
254
+ pnpm run docs:dev # run documentation site locally
255
+ ```
256
+
257
+ Notes:
258
+ - `tsconfig.json` has `strict: true` enabled to enforce stricter TypeScript checks.
259
+ - Dependabot is configured to open weekly dependency PRs — you will review and merge them manually.
260
+ - CI should validate `build`, `typecheck`, `lint`, and `test` before merging PRs.
261
+
262
+ This repository also includes GitHub issue templates and a pull request template to help keep reports and contributions consistent.
263
+
249
264
  ## License
250
265
 
251
266
  [MIT](LICENSE) © [gonzyui](https://github.com/gonzyui)
@@ -1 +1 @@
1
- export { f as RedisCache, g as RedisCacheOptions, h as RedisLikeClient } from '../redis-AFbnh0Xa.mjs';
1
+ export { f as RedisCache, g as RedisCacheOptions, h as RedisLikeClient } from '../redis-UeRs8nqC.mjs';
@@ -1 +1 @@
1
- export { f as RedisCache, g as RedisCacheOptions, h as RedisLikeClient } from '../redis-AFbnh0Xa.js';
1
+ export { f as RedisCache, g as RedisCacheOptions, h as RedisLikeClient } from '../redis-UeRs8nqC.js';
@@ -8,7 +8,7 @@ var RedisCache = class {
8
8
  constructor(options) {
9
9
  this.client = options.client;
10
10
  this.prefix = options.prefix ?? "ani:";
11
- this.ttl = options.ttl ?? 86400;
11
+ this.ttl = options.ttl !== void 0 ? Math.floor(options.ttl / 1e3) : 86400;
12
12
  }
13
13
  prefixedKey(key) {
14
14
  return `${this.prefix}${key}`;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cache/redis.ts"],"names":[],"mappings":"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","file":"redis.js","sourcesContent":["import type { CacheAdapter } from \"../types\";\n\n/**\n * Minimal interface representing a Redis client.\n * Compatible with both `ioredis` and `redis` (node-redis v4+).\n */\nexport interface RedisLikeClient {\n get(key: string): Promise<string | null>;\n set(key: string, value: string, ...args: unknown[]): Promise<unknown>;\n del(...keys: (string | string[])[]): Promise<number>;\n keys(pattern: string): Promise<string[]>;\n /** Optional SCAN-based iteration — used when available to avoid blocking the server. */\n scanIterator?(options: { MATCH: string; COUNT?: number }): AsyncIterable<string>;\n}\n\nexport interface RedisCacheOptions {\n /** A Redis client instance (ioredis or node-redis). */\n client: RedisLikeClient;\n /** Key prefix to namespace ani-client entries (default: `\"ani:\"`) */\n prefix?: string;\n /** TTL in seconds (default: 86 400 = 24 h) */\n ttl?: number;\n}\n\n/**\n * Redis-backed cache adapter for AniListClient.\n *\n * @example\n * ```ts\n * import Redis from \"ioredis\";\n * import { AniListClient, RedisCache } from \"ani-client\";\n *\n * const redis = new Redis();\n * const client = new AniListClient({\n * cacheAdapter: new RedisCache({ client: redis }),\n * });\n * ```\n */\nexport class RedisCache implements CacheAdapter {\n private readonly client: RedisLikeClient;\n private readonly prefix: string;\n private readonly ttl: number;\n\n constructor(options: RedisCacheOptions) {\n this.client = options.client;\n this.prefix = options.prefix ?? \"ani:\";\n this.ttl = options.ttl ?? 86_400;\n }\n\n private prefixedKey(key: string): string {\n return `${this.prefix}${key}`;\n }\n\n async get<T>(key: string): Promise<T | undefined> {\n const raw = await this.client.get(this.prefixedKey(key));\n if (raw === null) return undefined;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return undefined;\n }\n }\n\n async set<T>(key: string, data: T): Promise<void> {\n await this.client.set(this.prefixedKey(key), JSON.stringify(data), \"EX\", this.ttl);\n }\n\n async delete(key: string): Promise<boolean> {\n const count = await this.client.del(this.prefixedKey(key));\n return count > 0;\n }\n\n /**\n * Collect keys matching a pattern. Uses SCAN when available, falls back to KEYS.\n *\n * **Warning:** The `KEYS` fallback is O(N) and blocks the Redis server.\n * Provide a client with `scanIterator` support for production use.\n * @internal\n */\n private async collectKeys(pattern: string): Promise<string[]> {\n if (this.client.scanIterator) {\n const keys: string[] = [];\n for await (const key of this.client.scanIterator({ MATCH: pattern, COUNT: 100 })) {\n keys.push(key);\n }\n return keys;\n }\n return this.client.keys(pattern);\n }\n\n async clear(): Promise<void> {\n const keys = await this.collectKeys(`${this.prefix}*`);\n if (keys.length > 0) {\n await this.client.del(...keys);\n }\n }\n\n /**\n * Get the actual number of keys with this prefix in Redis.\n */\n get size(): Promise<number> {\n return this.getSize();\n }\n\n /** @internal */\n private async getSize(): Promise<number> {\n const keys = await this.collectKeys(`${this.prefix}*`);\n return keys.length;\n }\n\n async keys(): Promise<string[]> {\n const raw = await this.collectKeys(`${this.prefix}*`);\n return raw.map((k) => k.slice(this.prefix.length));\n }\n\n /**\n * Remove all entries whose key matches the given pattern.\n *\n * - **String**: treated as a substring match (e.g. `\"Media\"` removes all keys containing `\"Media\"`).\n * - **RegExp**: tested against each key directly.\n *\n * @param pattern — A string (substring match) or RegExp.\n * @returns Number of entries removed.\n */\n async invalidate(pattern: string | RegExp): Promise<number> {\n if (typeof pattern === \"string\") {\n const keys = await this.collectKeys(`${this.prefix}*${pattern}*`);\n if (keys.length === 0) return 0;\n return this.client.del(...keys);\n }\n\n const allKeys = await this.collectKeys(`${this.prefix}*`);\n const matching = allKeys.filter((k) => pattern.test(k.slice(this.prefix.length)));\n if (matching.length === 0) return 0;\n return this.client.del(...matching);\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/cache/redis.ts"],"names":[],"mappings":"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","file":"redis.js","sourcesContent":["import type { CacheAdapter } from \"../types\";\n\n/**\n * Minimal interface representing a Redis client.\n * Compatible with both `ioredis` and `redis` (node-redis v4+).\n */\nexport interface RedisLikeClient {\n get(key: string): Promise<string | null>;\n set(key: string, value: string, ...args: unknown[]): Promise<unknown>;\n del(...keys: (string | string[])[]): Promise<number>;\n keys(pattern: string): Promise<string[]>;\n /** Optional SCAN-based iteration — used when available to avoid blocking the server. */\n scanIterator?(options: { MATCH: string; COUNT?: number }): AsyncIterable<string>;\n}\n\nexport interface RedisCacheOptions {\n /** A Redis client instance (ioredis or node-redis). */\n client: RedisLikeClient;\n /** Key prefix to namespace ani-client entries (default: `\"ani:\"`) */\n prefix?: string;\n /** TTL in milliseconds (default: 86 400 000 = 24h) */\n ttl?: number;\n}\n\n/**\n * Redis-backed cache adapter for AniListClient.\n *\n * @example\n * ```ts\n * import Redis from \"ioredis\";\n * import { AniListClient, RedisCache } from \"ani-client\";\n *\n * const redis = new Redis();\n * const client = new AniListClient({\n * cacheAdapter: new RedisCache({ client: redis }),\n * });\n * ```\n */\nexport class RedisCache implements CacheAdapter {\n private readonly client: RedisLikeClient;\n private readonly prefix: string;\n private readonly ttl: number;\n\n constructor(options: RedisCacheOptions) {\n this.client = options.client;\n this.prefix = options.prefix ?? \"ani:\";\n this.ttl = options.ttl !== undefined ? Math.floor(options.ttl / 1000) : 86_400;\n }\n\n private prefixedKey(key: string): string {\n return `${this.prefix}${key}`;\n }\n\n async get<T>(key: string): Promise<T | undefined> {\n const raw = await this.client.get(this.prefixedKey(key));\n if (raw === null) return undefined;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return undefined;\n }\n }\n\n async set<T>(key: string, data: T): Promise<void> {\n await this.client.set(this.prefixedKey(key), JSON.stringify(data), \"EX\", this.ttl);\n }\n\n async delete(key: string): Promise<boolean> {\n const count = await this.client.del(this.prefixedKey(key));\n return count > 0;\n }\n\n /**\n * Collect keys matching a pattern. Uses SCAN when available, falls back to KEYS.\n *\n * **Warning:** The `KEYS` fallback is O(N) and blocks the Redis server.\n * Provide a client with `scanIterator` support for production use.\n * @internal\n */\n private async collectKeys(pattern: string): Promise<string[]> {\n if (this.client.scanIterator) {\n const keys: string[] = [];\n for await (const key of this.client.scanIterator({ MATCH: pattern, COUNT: 100 })) {\n keys.push(key);\n }\n return keys;\n }\n return this.client.keys(pattern);\n }\n\n async clear(): Promise<void> {\n const keys = await this.collectKeys(`${this.prefix}*`);\n if (keys.length > 0) {\n await this.client.del(...keys);\n }\n }\n\n /**\n * Get the actual number of keys with this prefix in Redis.\n */\n get size(): Promise<number> {\n return this.getSize();\n }\n\n /** @internal */\n private async getSize(): Promise<number> {\n const keys = await this.collectKeys(`${this.prefix}*`);\n return keys.length;\n }\n\n async keys(): Promise<string[]> {\n const raw = await this.collectKeys(`${this.prefix}*`);\n return raw.map((k) => k.slice(this.prefix.length));\n }\n\n /**\n * Remove all entries whose key matches the given pattern.\n *\n * - **String**: treated as a substring match (e.g. `\"Media\"` removes all keys containing `\"Media\"`).\n * - **RegExp**: tested against each key directly.\n *\n * @param pattern — A string (substring match) or RegExp.\n * @returns Number of entries removed.\n */\n async invalidate(pattern: string | RegExp): Promise<number> {\n if (typeof pattern === \"string\") {\n const keys = await this.collectKeys(`${this.prefix}*${pattern}*`);\n if (keys.length === 0) return 0;\n return this.client.del(...keys);\n }\n\n const allKeys = await this.collectKeys(`${this.prefix}*`);\n const matching = allKeys.filter((k) => pattern.test(k.slice(this.prefix.length)));\n if (matching.length === 0) return 0;\n return this.client.del(...matching);\n }\n}\n"]}
@@ -6,7 +6,7 @@ var RedisCache = class {
6
6
  constructor(options) {
7
7
  this.client = options.client;
8
8
  this.prefix = options.prefix ?? "ani:";
9
- this.ttl = options.ttl ?? 86400;
9
+ this.ttl = options.ttl !== void 0 ? Math.floor(options.ttl / 1e3) : 86400;
10
10
  }
11
11
  prefixedKey(key) {
12
12
  return `${this.prefix}${key}`;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cache/redis.ts"],"names":[],"mappings":"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","file":"redis.mjs","sourcesContent":["import type { CacheAdapter } from \"../types\";\n\n/**\n * Minimal interface representing a Redis client.\n * Compatible with both `ioredis` and `redis` (node-redis v4+).\n */\nexport interface RedisLikeClient {\n get(key: string): Promise<string | null>;\n set(key: string, value: string, ...args: unknown[]): Promise<unknown>;\n del(...keys: (string | string[])[]): Promise<number>;\n keys(pattern: string): Promise<string[]>;\n /** Optional SCAN-based iteration — used when available to avoid blocking the server. */\n scanIterator?(options: { MATCH: string; COUNT?: number }): AsyncIterable<string>;\n}\n\nexport interface RedisCacheOptions {\n /** A Redis client instance (ioredis or node-redis). */\n client: RedisLikeClient;\n /** Key prefix to namespace ani-client entries (default: `\"ani:\"`) */\n prefix?: string;\n /** TTL in seconds (default: 86 400 = 24 h) */\n ttl?: number;\n}\n\n/**\n * Redis-backed cache adapter for AniListClient.\n *\n * @example\n * ```ts\n * import Redis from \"ioredis\";\n * import { AniListClient, RedisCache } from \"ani-client\";\n *\n * const redis = new Redis();\n * const client = new AniListClient({\n * cacheAdapter: new RedisCache({ client: redis }),\n * });\n * ```\n */\nexport class RedisCache implements CacheAdapter {\n private readonly client: RedisLikeClient;\n private readonly prefix: string;\n private readonly ttl: number;\n\n constructor(options: RedisCacheOptions) {\n this.client = options.client;\n this.prefix = options.prefix ?? \"ani:\";\n this.ttl = options.ttl ?? 86_400;\n }\n\n private prefixedKey(key: string): string {\n return `${this.prefix}${key}`;\n }\n\n async get<T>(key: string): Promise<T | undefined> {\n const raw = await this.client.get(this.prefixedKey(key));\n if (raw === null) return undefined;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return undefined;\n }\n }\n\n async set<T>(key: string, data: T): Promise<void> {\n await this.client.set(this.prefixedKey(key), JSON.stringify(data), \"EX\", this.ttl);\n }\n\n async delete(key: string): Promise<boolean> {\n const count = await this.client.del(this.prefixedKey(key));\n return count > 0;\n }\n\n /**\n * Collect keys matching a pattern. Uses SCAN when available, falls back to KEYS.\n *\n * **Warning:** The `KEYS` fallback is O(N) and blocks the Redis server.\n * Provide a client with `scanIterator` support for production use.\n * @internal\n */\n private async collectKeys(pattern: string): Promise<string[]> {\n if (this.client.scanIterator) {\n const keys: string[] = [];\n for await (const key of this.client.scanIterator({ MATCH: pattern, COUNT: 100 })) {\n keys.push(key);\n }\n return keys;\n }\n return this.client.keys(pattern);\n }\n\n async clear(): Promise<void> {\n const keys = await this.collectKeys(`${this.prefix}*`);\n if (keys.length > 0) {\n await this.client.del(...keys);\n }\n }\n\n /**\n * Get the actual number of keys with this prefix in Redis.\n */\n get size(): Promise<number> {\n return this.getSize();\n }\n\n /** @internal */\n private async getSize(): Promise<number> {\n const keys = await this.collectKeys(`${this.prefix}*`);\n return keys.length;\n }\n\n async keys(): Promise<string[]> {\n const raw = await this.collectKeys(`${this.prefix}*`);\n return raw.map((k) => k.slice(this.prefix.length));\n }\n\n /**\n * Remove all entries whose key matches the given pattern.\n *\n * - **String**: treated as a substring match (e.g. `\"Media\"` removes all keys containing `\"Media\"`).\n * - **RegExp**: tested against each key directly.\n *\n * @param pattern — A string (substring match) or RegExp.\n * @returns Number of entries removed.\n */\n async invalidate(pattern: string | RegExp): Promise<number> {\n if (typeof pattern === \"string\") {\n const keys = await this.collectKeys(`${this.prefix}*${pattern}*`);\n if (keys.length === 0) return 0;\n return this.client.del(...keys);\n }\n\n const allKeys = await this.collectKeys(`${this.prefix}*`);\n const matching = allKeys.filter((k) => pattern.test(k.slice(this.prefix.length)));\n if (matching.length === 0) return 0;\n return this.client.del(...matching);\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/cache/redis.ts"],"names":[],"mappings":"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","file":"redis.mjs","sourcesContent":["import type { CacheAdapter } from \"../types\";\n\n/**\n * Minimal interface representing a Redis client.\n * Compatible with both `ioredis` and `redis` (node-redis v4+).\n */\nexport interface RedisLikeClient {\n get(key: string): Promise<string | null>;\n set(key: string, value: string, ...args: unknown[]): Promise<unknown>;\n del(...keys: (string | string[])[]): Promise<number>;\n keys(pattern: string): Promise<string[]>;\n /** Optional SCAN-based iteration — used when available to avoid blocking the server. */\n scanIterator?(options: { MATCH: string; COUNT?: number }): AsyncIterable<string>;\n}\n\nexport interface RedisCacheOptions {\n /** A Redis client instance (ioredis or node-redis). */\n client: RedisLikeClient;\n /** Key prefix to namespace ani-client entries (default: `\"ani:\"`) */\n prefix?: string;\n /** TTL in milliseconds (default: 86 400 000 = 24h) */\n ttl?: number;\n}\n\n/**\n * Redis-backed cache adapter for AniListClient.\n *\n * @example\n * ```ts\n * import Redis from \"ioredis\";\n * import { AniListClient, RedisCache } from \"ani-client\";\n *\n * const redis = new Redis();\n * const client = new AniListClient({\n * cacheAdapter: new RedisCache({ client: redis }),\n * });\n * ```\n */\nexport class RedisCache implements CacheAdapter {\n private readonly client: RedisLikeClient;\n private readonly prefix: string;\n private readonly ttl: number;\n\n constructor(options: RedisCacheOptions) {\n this.client = options.client;\n this.prefix = options.prefix ?? \"ani:\";\n this.ttl = options.ttl !== undefined ? Math.floor(options.ttl / 1000) : 86_400;\n }\n\n private prefixedKey(key: string): string {\n return `${this.prefix}${key}`;\n }\n\n async get<T>(key: string): Promise<T | undefined> {\n const raw = await this.client.get(this.prefixedKey(key));\n if (raw === null) return undefined;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return undefined;\n }\n }\n\n async set<T>(key: string, data: T): Promise<void> {\n await this.client.set(this.prefixedKey(key), JSON.stringify(data), \"EX\", this.ttl);\n }\n\n async delete(key: string): Promise<boolean> {\n const count = await this.client.del(this.prefixedKey(key));\n return count > 0;\n }\n\n /**\n * Collect keys matching a pattern. Uses SCAN when available, falls back to KEYS.\n *\n * **Warning:** The `KEYS` fallback is O(N) and blocks the Redis server.\n * Provide a client with `scanIterator` support for production use.\n * @internal\n */\n private async collectKeys(pattern: string): Promise<string[]> {\n if (this.client.scanIterator) {\n const keys: string[] = [];\n for await (const key of this.client.scanIterator({ MATCH: pattern, COUNT: 100 })) {\n keys.push(key);\n }\n return keys;\n }\n return this.client.keys(pattern);\n }\n\n async clear(): Promise<void> {\n const keys = await this.collectKeys(`${this.prefix}*`);\n if (keys.length > 0) {\n await this.client.del(...keys);\n }\n }\n\n /**\n * Get the actual number of keys with this prefix in Redis.\n */\n get size(): Promise<number> {\n return this.getSize();\n }\n\n /** @internal */\n private async getSize(): Promise<number> {\n const keys = await this.collectKeys(`${this.prefix}*`);\n return keys.length;\n }\n\n async keys(): Promise<string[]> {\n const raw = await this.collectKeys(`${this.prefix}*`);\n return raw.map((k) => k.slice(this.prefix.length));\n }\n\n /**\n * Remove all entries whose key matches the given pattern.\n *\n * - **String**: treated as a substring match (e.g. `\"Media\"` removes all keys containing `\"Media\"`).\n * - **RegExp**: tested against each key directly.\n *\n * @param pattern — A string (substring match) or RegExp.\n * @returns Number of entries removed.\n */\n async invalidate(pattern: string | RegExp): Promise<number> {\n if (typeof pattern === \"string\") {\n const keys = await this.collectKeys(`${this.prefix}*${pattern}*`);\n if (keys.length === 0) return 0;\n return this.client.del(...keys);\n }\n\n const allKeys = await this.collectKeys(`${this.prefix}*`);\n const matching = allKeys.filter((k) => pattern.test(k.slice(this.prefix.length)));\n if (matching.length === 0) return 0;\n return this.client.del(...matching);\n }\n}\n"]}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { F as FuzzyDate, P as PageInfo, E as ExternalLink, C as CacheAdapter, a as CacheOptions, b as PagedResult, A as AniListClientOptions, R as RateLimitInfo, c as ResponseMeta, d as RateLimitOptions } from './redis-AFbnh0Xa.mjs';
2
- export { e as AniListHooks, L as Logger, f as RedisCache, g as RedisCacheOptions, h as RedisLikeClient } from './redis-AFbnh0Xa.mjs';
1
+ import { F as FuzzyDate, P as PageInfo, E as ExternalLink, C as CacheAdapter, a as CacheOptions, b as PagedResult, A as AniListClientOptions, R as RateLimitInfo, c as ResponseMeta, d as RateLimitOptions } from './redis-UeRs8nqC.mjs';
2
+ export { e as AniListHooks, L as Logger, f as RedisCache, g as RedisCacheOptions, h as RedisLikeClient } from './redis-UeRs8nqC.mjs';
3
3
 
4
4
  declare enum MediaListStatus {
5
5
  CURRENT = "CURRENT",
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { F as FuzzyDate, P as PageInfo, E as ExternalLink, C as CacheAdapter, a as CacheOptions, b as PagedResult, A as AniListClientOptions, R as RateLimitInfo, c as ResponseMeta, d as RateLimitOptions } from './redis-AFbnh0Xa.js';
2
- export { e as AniListHooks, L as Logger, f as RedisCache, g as RedisCacheOptions, h as RedisLikeClient } from './redis-AFbnh0Xa.js';
1
+ import { F as FuzzyDate, P as PageInfo, E as ExternalLink, C as CacheAdapter, a as CacheOptions, b as PagedResult, A as AniListClientOptions, R as RateLimitInfo, c as ResponseMeta, d as RateLimitOptions } from './redis-UeRs8nqC.js';
2
+ export { e as AniListHooks, L as Logger, f as RedisCache, g as RedisCacheOptions, h as RedisLikeClient } from './redis-UeRs8nqC.js';
3
3
 
4
4
  declare enum MediaListStatus {
5
5
  CURRENT = "CURRENT",
package/dist/index.js CHANGED
@@ -485,7 +485,7 @@ var RedisCache = class {
485
485
  constructor(options) {
486
486
  this.client = options.client;
487
487
  this.prefix = options.prefix ?? "ani:";
488
- this.ttl = options.ttl ?? 86400;
488
+ this.ttl = options.ttl !== void 0 ? Math.floor(options.ttl / 1e3) : 86400;
489
489
  }
490
490
  prefixedKey(key) {
491
491
  return `${this.prefix}${key}`;
@@ -2541,7 +2541,7 @@ function mapFavorites(fav) {
2541
2541
 
2542
2542
  // src/client/index.ts
2543
2543
  var DEFAULT_API_URL = "https://graphql.anilist.co";
2544
- var LIB_VERSION = "2.2.0" ;
2544
+ var LIB_VERSION = "2.2.1" ;
2545
2545
  var AniListClient = class {
2546
2546
  apiUrl;
2547
2547
  headers;
@@ -2654,7 +2654,8 @@ var AniListClient = class {
2654
2654
  throw error;
2655
2655
  }
2656
2656
  if (!res.ok || json.errors) {
2657
- const message = json.errors?.[0]?.message ?? `AniList API error (HTTP ${res.status})`;
2657
+ const msgs = (json.errors || []).map((e) => e.message).filter(Boolean);
2658
+ const message = msgs.length > 0 ? msgs.join(" | ") : `AniList API error (HTTP ${res.status})`;
2658
2659
  const error = new AniListError(message, res.status, json.errors ?? []);
2659
2660
  this.logger?.error("Request failed", { error: error.message, status: error.status });
2660
2661
  this.hooks.onError?.(error, query, variables);