anilink-api-wrapper 2.1.0 → 2.2.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/dist/AniLink.d.ts CHANGED
@@ -42,14 +42,26 @@ declare class AniLinkError extends Error {
42
42
  code: AniLinkErrorCode;
43
43
  /** Original Axios or transport error when raw diagnostics were enabled. */
44
44
  readonly rawAxiosError?: unknown;
45
+ /**
46
+ * Library-generated correlation ID joining this failure to the
47
+ * `onRequestStart`/`onResponse`/`onRetry`/`onError` hook events it
48
+ * produced, so a caught error can be matched to its lifecycle stream in a
49
+ * metrics or logging backend. Absent on errors raised outside the
50
+ * request pipeline (for example validation errors thrown before any
51
+ * request is sent).
52
+ */
53
+ readonly requestId?: string;
45
54
  /**
46
55
  * Creates a sanitized AniLink error.
47
56
  *
48
57
  * @param message - A safe message intended for application logs.
49
58
  * @param code - The stable code used to classify the failure.
50
59
  * @param rawAxiosError - The original Axios error when raw diagnostics are enabled.
60
+ * @param options - Additional error metadata such as the request correlation ID.
51
61
  */
52
- constructor(message: string, code: AniLinkErrorCode, rawAxiosError?: unknown);
62
+ constructor(message: string, code: AniLinkErrorCode, rawAxiosError?: unknown, options?: {
63
+ requestId?: string;
64
+ });
53
65
  }
54
66
  /**
55
67
  * Rate-limit accounting parsed from provider response headers.
@@ -89,16 +101,27 @@ declare class AniLinkApiError extends AniLinkError {
89
101
  * included in the error message so logs stay clean.
90
102
  */
91
103
  readonly rateLimit?: RateLimitInfo;
104
+ /**
105
+ * The `Content-Type` of the failing response, parsed from the upstream
106
+ * response headers. REST providers such as MyAnimeList return HTML or
107
+ * plain-text bodies on rate-limit and gateway error paths; this field lets
108
+ * consumers distinguish a structured JSON failure payload (where
109
+ * `data.message` is meaningful) from a non-JSON one without guessing.
110
+ * Absent when the response carried no `Content-Type` header.
111
+ */
112
+ readonly contentType?: string;
92
113
  /**
93
114
  * Creates an API error while preserving the upstream response body.
94
115
  *
95
116
  * @param status - The HTTP status returned by AniList.
96
117
  * @param data - The response body returned by AniList.
97
118
  * @param rawAxiosError - The original Axios error when raw diagnostics are enabled.
98
- * @param options - Additional error metadata such as rate-limit headers.
119
+ * @param options - Additional error metadata such as rate-limit headers and the response content type.
99
120
  */
100
121
  constructor(status: number, data: unknown, rawAxiosError?: unknown, options?: {
101
122
  rateLimit?: RateLimitInfo;
123
+ contentType?: string;
124
+ requestId?: string;
102
125
  });
103
126
  }
104
127
  /**
@@ -159,8 +182,13 @@ declare class AniLinkGraphQLError extends AniLinkApiError {
159
182
  * @param errors - The upstream GraphQL errors; each entry should carry a `message`.
160
183
  * @param data - The partial `data` object returned alongside the errors, when any. Exposed as {@link AniLinkGraphQLError.partialData}.
161
184
  * @param rawAxiosError - The original Axios error when raw diagnostics are enabled.
185
+ * @param options - Additional error metadata such as rate-limit headers and the response content type. AniList returns rate-limit headers even on HTTP 200 envelopes carrying GraphQL errors (for example a GraphQL-level `429`), so threading them here keeps {@link AniLinkGraphQLError.rateLimit} consistent with the HTTP-failure path.
162
186
  */
163
- constructor(errors: ReadonlyArray<GraphQLUpstreamError>, data?: unknown, rawAxiosError?: unknown);
187
+ constructor(errors: ReadonlyArray<GraphQLUpstreamError>, data?: unknown, rawAxiosError?: unknown, options?: {
188
+ rateLimit?: RateLimitInfo;
189
+ contentType?: string;
190
+ requestId?: string;
191
+ });
164
192
  }
165
193
  /**
166
194
  * Failure caused by a missing authentication token on a protected operation.
@@ -208,10 +236,12 @@ declare class AniLinkRestError extends AniLinkApiError {
208
236
  * @param status - The HTTP status returned by the upstream REST API.
209
237
  * @param data - The response body returned by the upstream REST API.
210
238
  * @param rawAxiosError - The original Axios error when raw diagnostics are enabled.
211
- * @param options - Additional error metadata such as rate-limit headers.
239
+ * @param options - Additional error metadata such as rate-limit headers, the response content type, and the request correlation ID.
212
240
  */
213
241
  constructor(status: number, data: unknown, rawAxiosError?: unknown, options?: {
214
242
  rateLimit?: RateLimitInfo;
243
+ contentType?: string;
244
+ requestId?: string;
215
245
  });
216
246
  }
217
247
  /**
@@ -222,6 +252,14 @@ declare class AniLinkRestError extends AniLinkApiError {
222
252
  interface AniLinkNetworkErrorOptions {
223
253
  /** The effective per-attempt timeout in milliseconds, when a timeout was configured and enforced. */
224
254
  timeoutMs?: number;
255
+ /**
256
+ * `true` when the abort happened during the post-success rate-limit
257
+ * pacing wait rather than while the request was in flight. The upstream
258
+ * request itself succeeded in that case, so consumers can distinguish
259
+ * "data was received but the caller's wait was cancelled" from a cancelled
260
+ * request. Absent for every other abort.
261
+ */
262
+ abortedDuringPacing?: boolean;
225
263
  }
226
264
  /**
227
265
  * Network, timeout, cancellation, or circuit-breaker failure.
@@ -237,15 +275,152 @@ declare class AniLinkNetworkError extends AniLinkError {
237
275
  * timeout is disabled (`0`) or the failure is not a timeout.
238
276
  */
239
277
  readonly timeoutMs?: number;
278
+ /**
279
+ * `true` when this abort happened during the post-success rate-limit
280
+ * pacing wait (see {@link AniLinkNetworkErrorOptions.abortedDuringPacing}).
281
+ * The upstream attempt already succeeded when this is set.
282
+ */
283
+ readonly abortedDuringPacing?: boolean;
240
284
  /**
241
285
  * Creates a sanitized transport error.
242
286
  *
243
287
  * @param code - The stable code for the transport failure.
244
288
  * @param message - A safe message intended for application logs.
245
289
  * @param rawAxiosError - The original Axios error when raw diagnostics are enabled.
246
- * @param options - Additional transport metadata such as the effective timeout duration.
290
+ * @param options - Additional transport metadata such as the effective timeout duration and the request correlation ID.
247
291
  */
248
- constructor(code: typeof AniLinkErrorCodes.NETWORK | typeof AniLinkErrorCodes.TIMEOUT | typeof AniLinkErrorCodes.ABORTED | typeof AniLinkErrorCodes.CIRCUIT, message: string, rawAxiosError?: unknown, options?: AniLinkNetworkErrorOptions);
292
+ constructor(code: typeof AniLinkErrorCodes.NETWORK | typeof AniLinkErrorCodes.TIMEOUT | typeof AniLinkErrorCodes.ABORTED | typeof AniLinkErrorCodes.CIRCUIT, message: string, rawAxiosError?: unknown, options?: AniLinkNetworkErrorOptions & {
293
+ requestId?: string;
294
+ });
295
+ }
296
+
297
+ /**
298
+ * Opt-in in-memory TTL response cache for read-heavy traversals.
299
+ *
300
+ * The cache is keyed by `(method, url, serialized body)` and capped by
301
+ * `maxEntries`. It is opt-in (off by default) and never caches mutations
302
+ * (`POST`/`PUT`/`DELETE`). Cache hits are observable through the existing
303
+ * `onResponse` hook via a `cacheHit` flag so consumers can distinguish a
304
+ * cached response from a network round-trip.
305
+ */
306
+ /**
307
+ * Configuration for the opt-in response cache.
308
+ */
309
+ interface ResponseCacheOptions {
310
+ /** The time-to-live for cached entries, in milliseconds. Defaults to 60_000 (1 minute). */
311
+ ttlMs?: number;
312
+ /** The maximum number of entries to retain. Defaults to 128. Entries are evicted LRU when the cap is reached. */
313
+ maxEntries?: number;
314
+ }
315
+ /**
316
+ * An in-memory TTL response cache with an LRU eviction cap.
317
+ *
318
+ * The cache is per-instance (one per `AniLink` client when enabled) so cache
319
+ * state never leaks across clients. Entries expire after `ttlMs` and the
320
+ * cache is capped at `maxEntries` with least-recently-used eviction.
321
+ *
322
+ * **Aliasing:** values returned from {@link ResponseCache.get} are deep
323
+ * clones of the cached entry, so a caller that mutates the returned object
324
+ * cannot corrupt the cached copy or affect subsequent reads.
325
+ *
326
+ * **Invalidation:** the cache is TTL-only. Mutations (`POST`/`PUT`/`DELETE`)
327
+ * sent through the same client do not invalidate cached `GET` responses, so
328
+ * a read-after-write sequence can return stale data for up to `ttlMs`. Use
329
+ * {@link ResponseCache.delete} for targeted invalidation, or
330
+ * {@link ResponseCache.clear} to drop everything. Keep `ttlMs` short for
331
+ * read-after-write-sensitive workloads.
332
+ *
333
+ * **Privacy:** the cache stores the full response body of every `GET`
334
+ * request when enabled, including authenticated user-scoped responses
335
+ * (for example `/Viewer`-style queries that return the user's profile or
336
+ * email). Cached bodies are retained in plaintext in the JS heap for up to
337
+ * `ttlMs` and are accessible to any code holding a reference to the
338
+ * `ResponseCache` instance. Entries are scoped by a SHA-256 hash of the
339
+ * bearer token so cached responses never cross identities, but within one
340
+ * identity sensitive payloads are retained verbatim. Do not enable the
341
+ * cache for clients that fetch private user data unless `ttlMs` is short
342
+ * and the cache instance is not shared across trust boundaries.
343
+ */
344
+ declare class ResponseCache {
345
+ private readonly entries;
346
+ private readonly ttlMs;
347
+ private readonly maxEntries;
348
+ /**
349
+ * Creates a response cache.
350
+ *
351
+ * @param options - Cache configuration; `ttlMs` defaults to 60_000, `maxEntries` to 128.
352
+ */
353
+ constructor(options?: ResponseCacheOptions);
354
+ /**
355
+ * Builds the cache key for a request.
356
+ *
357
+ * The serialized body is SHA-256 hashed (truncated to 16 hex chars)
358
+ * before it enters the key, so a credential-bearing GET body is never
359
+ * duplicated into the key string in plaintext — the key map retains
360
+ * entries for up to the TTL, outliving the error paths the rest of the
361
+ * library scrubs. The hash is deterministic, so equal bodies still share
362
+ * one entry and different bodies still get different entries.
363
+ *
364
+ * @param method - The HTTP method.
365
+ * @param url - The request URL.
366
+ * @param data - The request body, when present.
367
+ * @param authKey - An authentication-safe credential identity, so cached
368
+ * responses never cross bearer-token identities.
369
+ * @returns The cache key.
370
+ */
371
+ private static buildKey;
372
+ /**
373
+ * Reads a cached response for the given request, or `undefined` when the
374
+ * entry is absent or expired. Expired entries are evicted on read. The
375
+ * returned value is a deep clone of the cached entry, so a caller that
376
+ * mutates it cannot corrupt the cached copy or affect subsequent reads.
377
+ *
378
+ * @param method - The HTTP method.
379
+ * @param url - The request URL.
380
+ * @param data - The request body, when present.
381
+ * @param authKey - An authentication-safe credential identity, so cached
382
+ * responses never cross bearer-token identities.
383
+ * @returns A deep clone of the cached response body, or `undefined`.
384
+ */
385
+ get<T>(method: string, url: string, data?: object | string, authKey?: string): T | undefined;
386
+ /**
387
+ * Stores a response in the cache, evicting the LRU entry when the cap is
388
+ * reached. Only `GET` responses are cached; other methods are no-ops.
389
+ * The value is deep-copied on write; the cache never aliases the
390
+ * caller's object.
391
+ *
392
+ * @param method - The HTTP method.
393
+ * @param url - The request URL.
394
+ * @param data - The request body, when present.
395
+ * @param authKey - An authentication-safe credential identity, so cached
396
+ * responses never cross bearer-token identities.
397
+ * @param response - The response body to cache.
398
+ */
399
+ set<T>(method: string, url: string, data: object | string | undefined, authKey: string | undefined, response: T): void;
400
+ /**
401
+ * Removes the cached entry for the given request, if present. Use this
402
+ * for targeted invalidation after a mutation that changes the resource
403
+ * (for example a `POST` that updates the entity a cached `GET` returned).
404
+ * Only `GET` entries are tracked, so non-`GET` methods are a no-op and
405
+ * return `false`.
406
+ *
407
+ * @param method - The HTTP method.
408
+ * @param url - The request URL.
409
+ * @param data - The request body, when present.
410
+ * @param authKey - An authentication-safe credential identity, so cached
411
+ * responses never cross bearer-token identities.
412
+ * @returns `true` when an entry was removed, `false` when it was absent
413
+ * or the method is not cached.
414
+ */
415
+ delete(method: string, url: string, data?: object | string, authKey?: string): boolean;
416
+ /**
417
+ * Evicts the least-recently-used entry.
418
+ */
419
+ private evictLru;
420
+ /**
421
+ * Clears all cached entries.
422
+ */
423
+ clear(): void;
249
424
  }
250
425
 
251
426
  /**
@@ -294,12 +469,12 @@ interface RetryPolicy {
294
469
  * HTTP methods the shared transport accepts.
295
470
  *
296
471
  * GraphQL providers use `POST` only; REST providers additionally use `GET`,
297
- * `PUT`, and `DELETE`. The union is shared so hooks and error contexts stay
298
- * provider-agnostic.
472
+ * `PUT`, `PATCH`, and `DELETE`. The union is shared so hooks and error
473
+ * contexts stay provider-agnostic.
299
474
  *
300
475
  * @see {@link sendRequest}
301
476
  */
302
- type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
477
+ type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
303
478
  /**
304
479
  * Authentication material a provider can apply to an HTTP request.
305
480
  *
@@ -323,6 +498,13 @@ type RequestAuthInput = string | RequestAuth;
323
498
  * @see {@link OnErrorHandler}
324
499
  */
325
500
  interface RequestErrorContext {
501
+ /**
502
+ * Library-generated correlation ID identifying one logical request across
503
+ * all of its attempts. Use it to join `onRequestStart`, `onResponse`,
504
+ * `onError`, and `onRetry` events for the same request in a metrics or
505
+ * logging backend.
506
+ */
507
+ requestId: string;
326
508
  /** The URL the request was sent to. */
327
509
  url: string;
328
510
  /** The HTTP method of the request. */
@@ -335,6 +517,11 @@ interface RequestErrorContext {
335
517
  status?: number;
336
518
  /** The delay before the next retry, when the failure will be retried. */
337
519
  nextDelayMs?: number;
520
+ /**
521
+ * Rate-limit accounting parsed from the failure response's
522
+ * `x-ratelimit-*` headers, when the upstream included them.
523
+ */
524
+ rateLimit?: RateLimitInfo;
338
525
  }
339
526
  /**
340
527
  * Callback invoked when an attempt fails, before each retry wait and once more when retries are exhausted.
@@ -349,6 +536,11 @@ type OnErrorHandler = (error: AniLinkError, context: RequestErrorContext) => voi
349
536
  * @see {@link OnRequestStartHandler}
350
537
  */
351
538
  interface RequestContext {
539
+ /**
540
+ * Library-generated correlation ID identifying one logical request across
541
+ * all of its attempts; see {@link RequestErrorContext.requestId}.
542
+ */
543
+ requestId: string;
352
544
  /** The URL the request is being sent to. */
353
545
  url: string;
354
546
  /** The HTTP method of the request. */
@@ -364,14 +556,64 @@ interface RequestContext {
364
556
  */
365
557
  type OnRequestStartHandler = (context: RequestContext) => void;
366
558
  /**
367
- * A callback invoked after each attempt completes, whether it succeeded or
368
- * failed. The elapsed wall-clock time of the attempt is reported as
369
- * `durationMs`, making this the natural point for latency metrics.
559
+ * A callback invoked after each attempt completes with the elapsed
560
+ * `durationMs` and parsed `rateLimit` headers when present. When the response
561
+ * was served from the opt-in response cache, `cacheHit` is `true` and
562
+ * `durationMs` is `0`.
370
563
  *
371
564
  * @see {@link RequestOptions.onResponse}
372
565
  */
373
566
  type OnResponseHandler = (context: RequestContext & {
374
567
  durationMs: number;
568
+ rateLimit?: RateLimitInfo;
569
+ cacheHit?: boolean;
570
+ }) => void;
571
+ /**
572
+ * A callback invoked when proactive rate-limit pacing delays the next request
573
+ * after a successful attempt, with the pacing wait in `delayMs`.
574
+ *
575
+ * @see {@link RequestOptions.onPace}
576
+ */
577
+ type OnPaceHandler = (context: RequestContext & {
578
+ delayMs: number;
579
+ }) => void;
580
+ /**
581
+ * A callback invoked when a user-supplied lifecycle hook throws. Throwing
582
+ * hooks never affect the request pipeline; this callback only observes the
583
+ * failure so it can be routed to a logger or metrics backend. When unset,
584
+ * hook failures fall back to a `console.warn`.
585
+ *
586
+ * @see {@link RequestOptions.onHookError}
587
+ */
588
+ type OnHookErrorHandler = (hookName: string, error: unknown) => void;
589
+ /**
590
+ * Context passed to the `onCircuitOpen` hook when the circuit breaker trips.
591
+ *
592
+ * @see {@link OnCircuitOpenHandler}
593
+ */
594
+ interface CircuitOpenContext extends RequestContext {
595
+ /** The upstream host scope the breaker tripped for. */
596
+ host: string;
597
+ /** The consecutive-failure count that reached the threshold. */
598
+ failures: number;
599
+ }
600
+ /**
601
+ * A callback invoked when the circuit breaker opens (trips) after the
602
+ * consecutive-failure threshold is reached, so dashboards can plot trip
603
+ * frequency and time-to-half-open without scraping `CIRCUIT_OPEN_ERROR` codes.
604
+ *
605
+ * @see {@link RequestOptions.onCircuitOpen}
606
+ */
607
+ type OnCircuitOpenHandler = (context: CircuitOpenContext) => void;
608
+ /**
609
+ * A callback invoked when the circuit breaker closes (returns to healthy)
610
+ * after a successful post-cooldown probe, so dashboards can plot open
611
+ * duration and recovery without inferring it from error-code absence.
612
+ *
613
+ * @see {@link RequestOptions.onCircuitClose}
614
+ */
615
+ type OnCircuitCloseHandler = (context: RequestContext & {
616
+ host: string;
375
617
  }) => void;
376
618
  /**
377
619
  * Transport settings shared by the AniLink request operations.
@@ -455,10 +697,86 @@ interface RequestOptions {
455
697
  onRetry?: OnErrorHandler;
456
698
  /** Invoked just before each attempt is sent. */
457
699
  onRequestStart?: OnRequestStartHandler;
458
- /** Invoked after each attempt completes with the elapsed `durationMs`. */
700
+ /** Invoked after each attempt completes with the elapsed `durationMs` and the parsed `rateLimit` headers when present. */
459
701
  onResponse?: OnResponseHandler;
702
+ /**
703
+ * Invoked when proactive rate-limit pacing ({@link RequestOptions.paceWithRateLimit})
704
+ * delays the next request after a successful attempt, with the pacing
705
+ * wait in `delayMs`.
706
+ */
707
+ onPace?: OnPaceHandler;
708
+ /**
709
+ * Invoked when a user-supplied lifecycle hook throws. Throwing hooks are
710
+ * always isolated from the request pipeline; this callback observes the
711
+ * failure so it can be routed to a logger or metrics backend. When unset,
712
+ * hook failures are reported via `console.warn`.
713
+ */
714
+ onHookError?: OnHookErrorHandler;
715
+ /**
716
+ * Invoked when the circuit breaker opens (trips) after the
717
+ * consecutive-failure threshold is reached. Carries the host scope and
718
+ * the failure count so consumers can plot trip frequency and alert on
719
+ * sustained outages without parsing `CIRCUIT_OPEN_ERROR` codes.
720
+ *
721
+ * @see {@link OnCircuitOpenHandler}
722
+ */
723
+ onCircuitOpen?: OnCircuitOpenHandler;
724
+ /**
725
+ * Invoked when the circuit breaker closes (returns to healthy) after a
726
+ * successful post-cooldown probe, so consumers can plot open duration and
727
+ * recovery without inferring it from error-code absence.
728
+ *
729
+ * @see {@link OnCircuitCloseHandler}
730
+ */
731
+ onCircuitClose?: OnCircuitCloseHandler;
732
+ /**
733
+ * Bypass the shared rate-limit pacing deadline recorded by a prior
734
+ * successful response to the same host, so an urgent single request
735
+ * (for example a user-facing lookup during a rate-limited window) is not
736
+ * held hostage by a deadline recorded from an earlier bulk request on
737
+ * the same client. Defaults to `false`; the per-request `signal` is still
738
+ * honored.
739
+ *
740
+ * @see {@link RequestOptions.paceWithRateLimit}
741
+ */
742
+ ignorePaceDeadline?: boolean;
743
+ /**
744
+ * Opt-in in-memory TTL response cache for read-heavy traversals. When
745
+ * set, `GET` responses are cached by `(method, url, serialized body)`
746
+ * for the cache's TTL window so repeated identical reads skip the network
747
+ * round-trip entirely. Mutations (`POST`/`PUT`/`DELETE`) are never cached.
748
+ * Off by default; pass a `ResponseCache` instance to enable.
749
+ *
750
+ * **Privacy:** the cache retains the full response body of every cached
751
+ * `GET` in plaintext for the TTL window, including authenticated
752
+ * user-scoped responses. Entries are scoped by a hash of the bearer
753
+ * token so they never cross identities, but within one identity
754
+ * sensitive payloads are retained. Do not enable for clients that fetch
755
+ * private user data unless the TTL is short and the cache instance is
756
+ * not shared across trust boundaries.
757
+ *
758
+ * @see {@link ResponseCache}
759
+ */
760
+ responseCache?: ResponseCache;
460
761
  }
461
762
 
763
+ /**
764
+ * Destroys every cached custom agent pair — plus every pair evicted while
765
+ * requests may still have been in flight — and clears the cache. Intended
766
+ * for tests and explicit teardown so long-lived processes can release the
767
+ * keep-alive sockets held by customized agents on demand.
768
+ *
769
+ * **Must not be called while requests using these agents are in-flight.**
770
+ * The agents are shared across every request with identical
771
+ * `maxSockets`/`maxFreeSockets` bounds, so destroying them closes the
772
+ * underlying sockets and can fail concurrent requests that are still
773
+ * draining over those sockets. Call this only after all in-flight requests
774
+ * have settled (for example in a shutdown hook that has awaited the final
775
+ * request, or in test teardown after the test's assertions). Calling it
776
+ * twice is safe (the second call iterates an empty cache).
777
+ */
778
+ declare const destroyCachedAgents: () => void;
779
+
462
780
  /**
463
781
  * The `custom` member group of the `AniListApi` type.
464
782
  *
@@ -8841,7 +9159,7 @@ type AniListQueries = {
8841
9159
  /**
8842
9160
  * `GenreCollectionQuery` returns the list of all genres recognized by AniList. No variables are required.
8843
9161
  * @param options - Optional per-request transport settings ({@link RequestOptions}) merged over the instance-level ones for this call only.
8844
- * @returns {Promise<string>} A promise that resolves to the genre collection data.
9162
+ * @returns {Promise<string[]>} A promise that resolves to the genre collection data (a list of genre strings).
8845
9163
  *
8846
9164
  * @example
8847
9165
  * ```typescript
@@ -8849,7 +9167,7 @@ type AniListQueries = {
8849
9167
  * ```
8850
9168
  * @see https://docs.anilist.co/reference/query
8851
9169
  */
8852
- genreCollection: (options?: RequestOptions) => Promise<string>;
9170
+ genreCollection: (options?: RequestOptions) => Promise<string[]>;
8853
9171
  /**
8854
9172
  * `MediaTagCollectionQuery` returns all media tags recognized by AniList, optionally filtered by `variables`. Returns a {@link MediaTagCollectionResponse}.
8855
9173
  * @param {MediaTagCollectionVariables} variables - Optional {@link MediaTagCollectionVariables} filters for the query.
@@ -8876,7 +9194,7 @@ type AniListQueries = {
8876
9194
  * Must be authenticated.
8877
9195
  * @see https://docs.anilist.co/reference/object/user
8878
9196
  */
8879
- viewer: (variables: UserVariables, options?: RequestOptions) => Promise<UserResponse>;
9197
+ viewer: (variables?: UserVariables, options?: RequestOptions) => Promise<UserResponse>;
8880
9198
  /**
8881
9199
  * `NotificationQuery` fetches a single notification by `id`. Returns a {@link NotificationResponse}. Must be authenticated.
8882
9200
  * @param {NotificationVariables} variables - The {@link NotificationVariables} for the query.
@@ -11414,17 +11732,49 @@ interface PaginateOptions {
11414
11732
  perPage?: number;
11415
11733
  /** 1-based page number to start from. Defaults to 1. */
11416
11734
  startPage?: number;
11417
- /** Hard cap on pages fetched, guarding against unbounded loops. Defaults to 100. */
11735
+ /**
11736
+ * Hard cap on pages fetched, guarding against unbounded loops. Defaults
11737
+ * to 100, which means up to 100 round-trips (up to 5,000 items at the
11738
+ * default `perPage`); set an explicit value for cost-sensitive workloads.
11739
+ */
11418
11740
  maxPages?: number;
11419
11741
  /**
11420
11742
  * Maximum number of page requests kept in flight at once while collecting
11421
11743
  * results. Pages are always returned in order regardless of completion
11422
11744
  * order, scheduling stops as soon as a fetched page reports
11423
11745
  * `hasNextPage: false`, and every existing guard (`maxPages`, `perPage`
11424
- * clamping) still applies. Defaults to `1` (strictly sequential fetches,
11425
- * matching previous behavior). Values above 8 are clamped down to 8.
11746
+ * clamping) still applies. Defaults to `3`
11747
+ * (a small look-ahead window); pass `1` for strictly sequential fetches.
11748
+ * Values above 8 are clamped down to 8.
11426
11749
  */
11427
11750
  concurrency?: number;
11751
+ /**
11752
+ * Optional `AbortSignal` to cancel the traversal. When aborted, all
11753
+ * in-flight look-ahead page requests are cancelled immediately so they
11754
+ * stop consuming rate-limit budget and bandwidth for payloads that will
11755
+ * be discarded. The signal is also forwarded to `fetchPage` calls so the
11756
+ * transport layer can abort the underlying HTTP request.
11757
+ */
11758
+ signal?: AbortSignal;
11759
+ /**
11760
+ * Optional per-page callback invoked once per page **after all responses
11761
+ * have been collected**, as the results are gathered into the returned
11762
+ * `PaginateResult`. This is a post-collection notification, not a
11763
+ * streaming hook: because the eager helpers collect every response before
11764
+ * returning, this callback does **not** reduce peak memory or release
11765
+ * collected items incrementally. For true streaming, early-exit, or
11766
+ * memory-bounded workflows, use {@link paginatePages} instead — it yields
11767
+ * each page as it arrives and lets the consumer `break` or `return` to
11768
+ * stop the traversal. The callback receives the page's `pageInfo` and
11769
+ * items array; the full `PaginateResult` is still returned for callers
11770
+ * that need the collected items. Errors thrown by the callback are
11771
+ * caught, reported via `console.warn`, and swallowed, so a failing
11772
+ * observer cannot fail {@link paginate} or stop the traversal.
11773
+ */
11774
+ onPage?: (page: {
11775
+ pageInfo: PageInfo;
11776
+ items: unknown[];
11777
+ }) => void;
11428
11778
  }
11429
11779
  /** Options controlling a {@link paginateChunks} traversal over `hasNextChunk`-based chunks. */
11430
11780
  interface ChunkPaginateOptions {
@@ -11435,17 +11785,49 @@ interface ChunkPaginateOptions {
11435
11785
  perChunk?: number;
11436
11786
  /** 1-based chunk number to start from. Defaults to 1. */
11437
11787
  startChunk?: number;
11438
- /** Hard cap on chunks fetched, guarding against unbounded loops. Defaults to 100. */
11788
+ /**
11789
+ * Hard cap on chunks fetched, guarding against unbounded loops. Defaults
11790
+ * to 100, which means up to 100 round-trips and up to 50,000 items at the
11791
+ * default `perChunk`; set an explicit value for cost-sensitive workloads.
11792
+ */
11439
11793
  maxChunks?: number;
11440
11794
  /**
11441
11795
  * Maximum number of chunk requests kept in flight at once while collecting
11442
11796
  * results. Chunks are always returned in order regardless of completion
11443
11797
  * order, scheduling stops as soon as a fetched chunk reports
11444
11798
  * `hasNextChunk: false`, and every existing guard (`maxChunks`, `perChunk`
11445
- * clamping) still applies. Defaults to `1` (strictly sequential fetches,
11446
- * matching previous behavior). Values above 8 are clamped down to 8.
11799
+ * clamping) still applies. Defaults to `3`
11800
+ * (a small look-ahead window); pass `1` for strictly sequential fetches.
11801
+ * Values above 8 are clamped down to 8.
11447
11802
  */
11448
11803
  concurrency?: number;
11804
+ /**
11805
+ * Optional `AbortSignal` to cancel the traversal. When aborted, all
11806
+ * in-flight look-ahead chunk requests are cancelled immediately so they
11807
+ * stop consuming rate-limit budget and bandwidth for payloads that will
11808
+ * be discarded.
11809
+ */
11810
+ signal?: AbortSignal;
11811
+ /**
11812
+ * Optional per-chunk callback invoked once per chunk **after all responses
11813
+ * have been collected**, as the results are gathered into the returned
11814
+ * `ChunkPaginateResult`. This is a post-collection notification, not a
11815
+ * streaming hook: because the eager helpers collect every response before
11816
+ * returning, this callback does **not** reduce peak memory or release
11817
+ * collected items incrementally. For true streaming, early-exit, or
11818
+ * memory-bounded workflows, use {@link paginatePages} instead — it yields
11819
+ * each page as it arrives and lets the consumer `break` or `return` to
11820
+ * stop the traversal. The callback receives the chunk's `hasNextChunk`
11821
+ * flag and items array; the full `ChunkPaginateResult` is still returned
11822
+ * for callers that need the collected items. Errors thrown by the
11823
+ * callback are caught, reported via `console.warn`, and swallowed, so a
11824
+ * failing observer cannot fail {@link paginateChunks} or stop the
11825
+ * traversal.
11826
+ */
11827
+ onChunk?: (chunk: {
11828
+ hasNextChunk: boolean;
11829
+ items: unknown[];
11830
+ }) => void;
11449
11831
  }
11450
11832
  /** The outcome of a {@link paginate} traversal. */
11451
11833
  interface PaginateResult<TItem> {
@@ -11482,19 +11864,21 @@ interface ChunkPaginateResult<TItem> {
11482
11864
  * array at `itemsKey`, and stops when AniList reports no further pages or when the
11483
11865
  * `maxPages` guard fires. The guard prevents accidental unbounded fetch loops.
11484
11866
  * Pass `concurrency` to keep multiple page requests in flight at once; results
11485
- * are still collected strictly in page order.
11867
+ * are still collected strictly in page order. The default `maxPages` of 100
11868
+ * means an unconstrained traversal can issue up to 100 round-trips; set an
11869
+ * explicit `maxPages` for cost-sensitive workloads.
11486
11870
  *
11487
11871
  * @typeParam TPage - The page response shape (must include `pageInfo`).
11488
11872
  * @typeParam K - The key of the items array on `TPage`.
11489
- * @param fetchPage - Callback that fetches a single page given its 1-based number and `perPage`.
11873
+ * @param fetchPage - Callback that fetches a single page given its 1-based number, `perPage`, and an optional `AbortSignal` forwarded from the traversal.
11490
11874
  * @param itemsKey - The key of the items array on the page response (e.g. `"media"`, `"users"`).
11491
- * @param options - Optional `perPage`, `startPage`, `maxPages`, and `concurrency` controls.
11875
+ * @param options - Optional `perPage`, `startPage`, `maxPages`, `concurrency`, `signal`, and `onPage` controls.
11492
11876
  * @returns The collected items, per-page snapshots, page count, and whether the guard truncated the run.
11493
11877
  * @see https://docs.anilist.co/reference/object/pageinfo
11494
11878
  * @example
11495
11879
  * ```typescript
11496
11880
  * const result = await paginate(
11497
- * (page, perPage) => aniLink.anilist.query.page.medias({ page, perPage, type: "ANIME" }),
11881
+ * (page, perPage, signal) => aniLink.anilist.query.page.medias({ page, perPage, type: "ANIME" }, { signal }),
11498
11882
  * "media",
11499
11883
  * { perPage: 50, maxPages: 10, concurrency: 4 }
11500
11884
  * );
@@ -11503,23 +11887,32 @@ interface ChunkPaginateResult<TItem> {
11503
11887
  */
11504
11888
  declare function paginate<TPage extends {
11505
11889
  pageInfo: PageInfo;
11506
- }, K extends ArrayKeys<TPage> & keyof TPage>(fetchPage: (page: number, perPage: number) => Promise<TPage>, itemsKey: K, options?: PaginateOptions): Promise<PaginateResult<ArrayElement<TPage, K>>>;
11890
+ }, K extends ArrayKeys<TPage> & keyof TPage>(fetchPage: (page: number, perPage: number, signal?: AbortSignal) => Promise<TPage>, itemsKey: K, options?: PaginateOptions): Promise<PaginateResult<ArrayElement<TPage, K>>>;
11507
11891
  /**
11508
11892
  * Async generator that yields each {@link PageInfo}-based page response until
11509
11893
  * `hasNextPage` is false or `maxPages` is reached.
11510
11894
  *
11511
11895
  * Use this for streaming or early-exit workflows where collecting every item
11512
- * into memory is unnecessary. The `maxPages` guard still prevents unbounded loops.
11896
+ * into memory is unnecessary. The `maxPages` guard still prevents unbounded
11897
+ * loops. Unlike the sequential implementations it replaces, this generator
11898
+ * keeps a small look-ahead window of `concurrency` in-flight page requests so
11899
+ * round-trip latency overlaps while pages are still yielded strictly in page
11900
+ * order; on early exit (`break`/`return` by the consumer), a terminal page,
11901
+ * or the `maxPages` guard, already-launched stragglers are drained and their
11902
+ * payloads discarded.
11903
+ *
11904
+ * The default `maxPages` of 100 means an unconstrained traversal can issue up
11905
+ * to 100 round-trips; set an explicit `maxPages` for cost-sensitive workloads.
11513
11906
  *
11514
11907
  * @typeParam TPage - The page response shape (must include `pageInfo`).
11515
- * @param fetchPage - Callback that fetches a single page given its 1-based number and `perPage`.
11516
- * @param options - Optional `perPage`, `startPage`, and `maxPages` controls.
11517
- * @yields Each raw page response in turn.
11908
+ * @param fetchPage - Callback that fetches a single page given its 1-based number, `perPage`, and an optional `AbortSignal` forwarded from the traversal.
11909
+ * @param options - Optional `perPage`, `startPage`, `maxPages`, `concurrency`, and `signal` controls. `concurrency` defaults to a small look-ahead window; pass `1` for strictly sequential fetches.
11910
+ * @yields Each raw page response in turn, in page order.
11518
11911
  * @see https://docs.anilist.co/reference/object/pageinfo
11519
11912
  * @example
11520
11913
  * ```typescript
11521
11914
  * for await (const page of paginatePages(
11522
- * (page, perPage) => aniLink.anilist.query.page.medias({ page, perPage, type: "ANIME" })
11915
+ * (page, perPage, signal) => aniLink.anilist.query.page.medias({ page, perPage, type: "ANIME" }, { signal })
11523
11916
  * )) {
11524
11917
  * console.log(page.pageInfo.currentPage, page.media.length);
11525
11918
  * if (page.media.length > 0 && page.media[0].id === 1) break;
@@ -11528,7 +11921,7 @@ declare function paginate<TPage extends {
11528
11921
  */
11529
11922
  declare function paginatePages<TPage extends {
11530
11923
  pageInfo: PageInfo;
11531
- }>(fetchPage: (page: number, perPage: number) => Promise<TPage>, options?: PaginateOptions): AsyncGenerator<TPage>;
11924
+ }>(fetchPage: (page: number, perPage: number, signal?: AbortSignal) => Promise<TPage>, options?: PaginateOptions): AsyncGenerator<TPage>;
11532
11925
  /**
11533
11926
  * Iterate `MediaListCollection` chunks until `hasNextChunk` is false or `maxChunks` is reached.
11534
11927
  *
@@ -11537,20 +11930,23 @@ declare function paginatePages<TPage extends {
11537
11930
  * extracts the items array at `itemsKey` (typically `"lists"`), and stops when AniList
11538
11931
  * reports no further chunks or when the `maxChunks` guard fires. Pass
11539
11932
  * `concurrency` to keep multiple chunk requests in flight at once; results are
11540
- * still collected strictly in chunk order.
11933
+ * still collected strictly in chunk order. The default `maxChunks` of 100
11934
+ * means an unconstrained traversal can issue up to 100 round-trips (up to
11935
+ * 50,000 items at the default `perChunk`); set an explicit `maxChunks` for
11936
+ * cost-sensitive workloads.
11541
11937
  *
11542
11938
  * @typeParam TChunk - The chunk response shape (must include `hasNextChunk`).
11543
11939
  * @typeParam K - The key of the items array on `TChunk`.
11544
- * @param fetchChunk - Callback that fetches a single chunk given its 1-based number and `perChunk`.
11940
+ * @param fetchChunk - Callback that fetches a single chunk given its 1-based number, `perChunk`, and an optional `AbortSignal` forwarded from the traversal.
11545
11941
  * @param itemsKey - The key of the items array on the chunk response (e.g. `"lists"`).
11546
- * @param options - Optional `perChunk`, `startChunk`, `maxChunks`, and `concurrency` controls.
11942
+ * @param options - Optional `perChunk`, `startChunk`, `maxChunks`, `concurrency`, `signal`, and `onChunk` controls.
11547
11943
  * @returns The collected items, per-chunk snapshots, chunk count, and whether the guard truncated the run.
11548
11944
  * @see https://docs.anilist.co/reference/object/medialistcollection
11549
11945
  * @example
11550
11946
  * ```typescript
11551
11947
  * const result = await paginateChunks(
11552
- * (chunk, perChunk) => aniLink.anilist.query.mediaListCollection(
11553
- * { userId: 542244, type: "ANIME", chunk, perChunk }
11948
+ * (chunk, perChunk, signal) => aniLink.anilist.query.mediaListCollection(
11949
+ * { userId: 542244, type: "ANIME", chunk, perChunk }, { signal }
11554
11950
  * ),
11555
11951
  * "lists",
11556
11952
  * { perChunk: 500, maxChunks: 20, concurrency: 3 }
@@ -11560,7 +11956,7 @@ declare function paginatePages<TPage extends {
11560
11956
  */
11561
11957
  declare function paginateChunks<TChunk extends {
11562
11958
  hasNextChunk: boolean;
11563
- }, K extends ArrayKeys<TChunk> & keyof TChunk>(fetchChunk: (chunk: number, perChunk: number) => Promise<TChunk>, itemsKey: K, options?: ChunkPaginateOptions): Promise<ChunkPaginateResult<ArrayElement<TChunk, K>>>;
11959
+ }, K extends ArrayKeys<TChunk> & keyof TChunk>(fetchChunk: (chunk: number, perChunk: number, signal?: AbortSignal) => Promise<TChunk>, itemsKey: K, options?: ChunkPaginateOptions): Promise<ChunkPaginateResult<ArrayElement<TChunk, K>>>;
11564
11960
 
11565
11961
  /**
11566
11962
  * The pagination and pure-helper members of the `AniListApi` type.
@@ -11675,10 +12071,13 @@ type AniListHelpers = {
11675
12071
  /**
11676
12072
  * AniList provider facade.
11677
12073
  *
11678
- * Adding an operation touches four sites: the operation class under `query/`
11679
- * or `mutation/`, its declaration on one of the group types under `facade/`
11680
- * (composed into {@link AniListApi} below), and its instance wiring in
11681
- * `wiring.ts`.
12074
+ * Adding an operation touches three sites: the operation class under `query/`
12075
+ * or `mutation/`, its entry in the declarative registry in `registry.ts`, and
12076
+ * its declaration on one of the group types under `facade/` (composed into
12077
+ * {@link AniListApi} below). Instance wiring in `wiring.ts` is automatic from
12078
+ * the registry, and the group modules carry a compile-time
12079
+ * `Record<RegistryXxxKeys, true>` parity constant so the registry
12080
+ * and the typed surface cannot drift without failing `tsc`.
11682
12081
  */
11683
12082
 
11684
12083
  /**
@@ -11714,11 +12113,12 @@ type AniLinkOptions = RequestOptions;
11714
12113
  type AniListApi = AniListCustom & AniListQueries & AniListMutations & AniListHelpers;
11715
12114
 
11716
12115
  /**
11717
- * {@link MalPicture} is the image variants returned by MyAnimeList for an anime entity.
12116
+ * {@link MalPicture} is the image variants returned by MyAnimeList for an anime or manga entity.
11718
12117
  *
11719
- * It is the `main_picture` shape inside {@link MalAnime} and is selected via {@link MalRequestOptions.fields} through `MalAnimeOperation.get` and `MyAnimeListAnimeApi.get`.
12118
+ * It is the `main_picture` shape inside {@link MalAnime} and {@link MalManga} and is selected via {@link MalRequestOptions.fields} through `MalAnimeOperation.get`, `MalMangaOperation.get`, `MyAnimeListAnimeApi.get`, and `MyAnimeListMangaApi.get`.
11720
12119
  *
11721
12120
  * @see https://myanimelist.net/apiconfig/references/api/v2#tag/anime/operation/anime_anime_id_get
12121
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/manga/operation/manga_manga_id_get
11722
12122
  */
11723
12123
  interface MalPicture {
11724
12124
  /** The large image URL, when MyAnimeList provides one. */
@@ -11761,6 +12161,39 @@ interface MalAnime {
11761
12161
  /** Any additional fields requested by a caller remain available without narrowing. */
11762
12162
  [field: string]: unknown;
11763
12163
  }
12164
+ /**
12165
+ * {@link MalManga} is the typed portion of a MyAnimeList manga response returned by `MalMangaOperation.get` and `MyAnimeListMangaApi.get`.
12166
+ *
12167
+ * It always carries `id` and `title`; additional fields appear when requested via {@link MalRequestOptions.fields} and are exposed through the index signature without narrowing. Manga-specific fields such as `num_chapters` and `num_volumes` mirror the MyAnimeList manga endpoint shape.
12168
+ *
12169
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/manga/operation/manga_manga_id_get
12170
+ */
12171
+ interface MalManga {
12172
+ /** The MyAnimeList numeric identifier. */
12173
+ id: number;
12174
+ /** The canonical MyAnimeList title. */
12175
+ title: string;
12176
+ /** Optional image variants requested through the `fields` query parameter. */
12177
+ main_picture?: MalPicture;
12178
+ /** The synopsis, when requested via the `fields` query parameter. */
12179
+ synopsis?: string;
12180
+ /** The publication status, when requested (one of MAL's status values such as `finished`). */
12181
+ status?: string;
12182
+ /** The average score out of 10, when requested via the `fields` query parameter. */
12183
+ mean?: number;
12184
+ /** The total number of chapters, when requested via the `fields` query parameter. */
12185
+ num_chapters?: number;
12186
+ /** The total number of volumes, when requested via the `fields` query parameter. */
12187
+ num_volumes?: number;
12188
+ /** The media type, when requested (for example `manga`, `novel`, or `oneshot`). */
12189
+ media_type?: string;
12190
+ /** The first publication date in ISO 8601 format, when requested via the `fields` query parameter. */
12191
+ start_date?: string;
12192
+ /** The end publication date in ISO 8601 format, when requested via the `fields` query parameter. */
12193
+ end_date?: string;
12194
+ /** Any additional fields requested by a caller remain available without narrowing. */
12195
+ [field: string]: unknown;
12196
+ }
11764
12197
  /**
11765
12198
  * {@link MalUser} is the typed portion of the authenticated MyAnimeList user response returned by `MalUserOperation.me` and `MyAnimeListUserApi.me`.
11766
12199
  *
@@ -11789,22 +12222,179 @@ interface MalUser {
11789
12222
  /**
11790
12223
  * {@link MalRequestOptions} is the public request options shared by MAL endpoint methods.
11791
12224
  *
11792
- * It extends {@link RequestOptions} with the MyAnimeList `fields` selector consumed by `MalAnimeOperation.get` and `MalUserOperation.me` through `MyAnimeListApi`. Transport settings are merged over the instance defaults from `MalCredentials` via `buildMyAnimeListApi`.
12225
+ * It extends {@link RequestOptions} with the MyAnimeList `fields` selector consumed by `MalAnimeOperation.get`, `MalMangaOperation.get`, and `MalUserOperation.me` through `MyAnimeListApi`. Transport settings are merged over the instance defaults from `MalCredentials` via `buildMyAnimeListApi`.
11793
12226
  *
11794
12227
  * @see https://myanimelist.net/apiconfig/references/api/v2#tag/anime/operation/anime_anime_id_get
12228
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/manga/operation/manga_manga_id_get
11795
12229
  * @see https://myanimelist.net/apiconfig/references/api/v2#tag/users/operation/users_user_id_get
11796
12230
  */
11797
12231
  interface MalRequestOptions extends RequestOptions {
11798
12232
  /** A comma-separated field selector, or the same selector as an array. */
11799
12233
  fields?: string | readonly string[];
11800
12234
  }
12235
+ /**
12236
+ * The watch status of an anime on a user's MyAnimeList list.
12237
+ *
12238
+ * These are the five fixed values MyAnimeList accepts for the `status` field
12239
+ * of {@link MalAnimeListStatusUpdate} and returns on {@link MalAnimeListStatus}.
12240
+ *
12241
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/user-animelist/operation/anime_anime_id_my_list_status_put
12242
+ */
12243
+ type MalAnimeListStatusValue = "watching" | "completed" | "on_hold" | "dropped" | "plan_to_watch";
12244
+ /**
12245
+ * {@link MalAnimeListStatusUpdate} is the form-urlencoded PATCH request body for updating a user's anime list status.
12246
+ *
12247
+ * Every field is optional: callers send only the fields they want to change. It is consumed by `MalAnimeOperation.updateMyListStatus` and `MyAnimeListAnimeApi.updateMyListStatus` against `PATCH /anime/{anime_id}/my_list_status`, which encodes it as `application/x-www-form-urlencoded` (MAL rejects JSON on this endpoint).
12248
+ *
12249
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/user-animelist/operation/anime_anime_id_my_list_status_put
12250
+ */
12251
+ interface MalAnimeListStatusUpdate {
12252
+ /** The watch status to set; one of {@link MalAnimeListStatusValue}. */
12253
+ status?: MalAnimeListStatusValue;
12254
+ /** The number of episodes the user has watched. */
12255
+ num_watched_episodes?: number;
12256
+ /** The user's score out of 10. */
12257
+ score?: number;
12258
+ /** The date the user started watching, in ISO 8601 form; MAL also accepts partial dates (`YYYY-MM` or `YYYY`). */
12259
+ start_date?: string;
12260
+ /** The date the user finished watching, in ISO 8601 form; MAL also accepts partial dates (`YYYY-MM` or `YYYY`). */
12261
+ finish_date?: string;
12262
+ /** Free-form notes the user attached to the entry. */
12263
+ comments?: string;
12264
+ /** Whether the user is currently rewatching the anime. */
12265
+ is_rewatching?: boolean;
12266
+ /** The number of times the user has rewatched the anime. */
12267
+ num_times_rewatched?: number;
12268
+ /** The rewatch value rating (0-5). */
12269
+ rewatch_value?: number;
12270
+ /** The priority rating (0-2). */
12271
+ priority?: number;
12272
+ /** User-defined tags attached to the entry; sent as a comma-separated string. */
12273
+ tags?: readonly string[];
12274
+ }
12275
+ /**
12276
+ * {@link MalAnimeListStatus} is the response returned by MyAnimeList for a user's anime list status.
12277
+ *
12278
+ * It is the shape returned by `MalAnimeOperation.updateMyListStatus` and `MyAnimeListAnimeApi.updateMyListStatus` from `PATCH /anime/{anime_id}/my_list_status`. MyAnimeList returns `tags` as a single comma-separated string and reports the episode count as `num_episodes_watched` (the request field is `num_watched_episodes` — a documented MAL asymmetry); the server-managed `updated_at` timestamp is included when set.
12279
+ *
12280
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/user-animelist/operation/anime_anime_id_my_list_status_put
12281
+ */
12282
+ interface MalAnimeListStatus {
12283
+ /** The current watch status; one of {@link MalAnimeListStatusValue}. */
12284
+ status: MalAnimeListStatusValue;
12285
+ /** The number of episodes the user has watched; MAL reports this as `num_episodes_watched`. */
12286
+ num_episodes_watched: number;
12287
+ /** The user's score out of 10. */
12288
+ score: number;
12289
+ /** The date the user started watching, in ISO 8601 form; may be a partial date (`YYYY-MM` or `YYYY`). */
12290
+ start_date?: string;
12291
+ /** The date the user finished watching, in ISO 8601 form; may be a partial date (`YYYY-MM` or `YYYY`). */
12292
+ finish_date?: string;
12293
+ /** Free-form notes the user attached to the entry. */
12294
+ comments?: string;
12295
+ /** Whether the user is currently rewatching the anime. */
12296
+ is_rewatching: boolean;
12297
+ /** The number of times the user has rewatched the anime. */
12298
+ num_times_rewatched: number;
12299
+ /** The rewatch value rating (0-5). */
12300
+ rewatch_value: number;
12301
+ /** The priority rating (0-2). */
12302
+ priority: number;
12303
+ /** User-defined tags attached to the entry, as a single comma-separated string. */
12304
+ tags: string;
12305
+ /** The server-managed timestamp of the last update, in ISO 8601 form. */
12306
+ updated_at?: string;
12307
+ /** Any additional fields returned by MyAnimeList remain available without narrowing. */
12308
+ [field: string]: unknown;
12309
+ }
12310
+ /**
12311
+ * The reading status of a manga on a user's MyAnimeList list.
12312
+ *
12313
+ * These are the five fixed values MyAnimeList accepts for the `status` field
12314
+ * of {@link MalMangaListStatusUpdate} and returns on {@link MalMangaListStatus}.
12315
+ *
12316
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/user-mangalist/operation/manga_manga_id_my_list_status_put
12317
+ */
12318
+ type MalMangaListStatusValue = "reading" | "completed" | "on_hold" | "dropped" | "plan_to_read";
12319
+ /**
12320
+ * {@link MalMangaListStatusUpdate} is the form-urlencoded PATCH request body for updating a user's manga list status.
12321
+ *
12322
+ * Every field is optional: callers send only the fields they want to change. It is consumed by `MalMangaOperation.updateMyListStatus` and `MyAnimeListMangaApi.updateMyListStatus` against `PATCH /manga/{manga_id}/my_list_status`, which encodes it as `application/x-www-form-urlencoded` (MAL rejects JSON on this endpoint).
12323
+ *
12324
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/user-mangalist/operation/manga_manga_id_my_list_status_put
12325
+ */
12326
+ interface MalMangaListStatusUpdate {
12327
+ /** The reading status to set; one of {@link MalMangaListStatusValue}. */
12328
+ status?: MalMangaListStatusValue;
12329
+ /** The number of chapters the user has read. */
12330
+ num_chapters_read?: number;
12331
+ /** The number of volumes the user has read. */
12332
+ num_volumes_read?: number;
12333
+ /** The user's score out of 10. */
12334
+ score?: number;
12335
+ /** The date the user started reading, in ISO 8601 form; MAL also accepts partial dates (`YYYY-MM` or `YYYY`). */
12336
+ start_date?: string;
12337
+ /** The date the user finished reading, in ISO 8601 form; MAL also accepts partial dates (`YYYY-MM` or `YYYY`). */
12338
+ finish_date?: string;
12339
+ /** Free-form notes the user attached to the entry. */
12340
+ comments?: string;
12341
+ /** Whether the user is currently rereading the manga. */
12342
+ is_rereading?: boolean;
12343
+ /** The number of times the user has reread the manga. */
12344
+ num_times_reread?: number;
12345
+ /** The reread value rating (0-5). */
12346
+ reread_value?: number;
12347
+ /** The priority rating (0-2). */
12348
+ priority?: number;
12349
+ /** User-defined tags attached to the entry; sent as a comma-separated string. */
12350
+ tags?: readonly string[];
12351
+ }
12352
+ /**
12353
+ * {@link MalMangaListStatus} is the response returned by MyAnimeList for a user's manga list status.
12354
+ *
12355
+ * It is the shape returned by `MalMangaOperation.updateMyListStatus` and `MyAnimeListMangaApi.updateMyListStatus` from `PATCH /manga/{manga_id}/my_list_status`. MyAnimeList returns `tags` as a single comma-separated string and reports the chapter count as `num_chapters_read`; the server-managed `updated_at` timestamp is included when set.
12356
+ *
12357
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/user-mangalist/operation/manga_manga_id_my_list_status_put
12358
+ */
12359
+ interface MalMangaListStatus {
12360
+ /** The current reading status; one of {@link MalMangaListStatusValue}. */
12361
+ status: MalMangaListStatusValue;
12362
+ /** The number of chapters the user has read. */
12363
+ num_chapters_read: number;
12364
+ /** The number of volumes the user has read. */
12365
+ num_volumes_read: number;
12366
+ /** The user's score out of 10. */
12367
+ score: number;
12368
+ /** The date the user started reading, in ISO 8601 form; may be a partial date (`YYYY-MM` or `YYYY`). */
12369
+ start_date?: string;
12370
+ /** The date the user finished reading, in ISO 8601 form; may be a partial date (`YYYY-MM` or `YYYY`). */
12371
+ finish_date?: string;
12372
+ /** Free-form notes the user attached to the entry. */
12373
+ comments?: string;
12374
+ /** Whether the user is currently rereading the manga. */
12375
+ is_rereading: boolean;
12376
+ /** The number of times the user has reread the manga. */
12377
+ num_times_reread: number;
12378
+ /** The reread value rating (0-5). */
12379
+ reread_value: number;
12380
+ /** The priority rating (0-2). */
12381
+ priority: number;
12382
+ /** User-defined tags attached to the entry, as a single comma-separated string. */
12383
+ tags: string;
12384
+ /** The server-managed timestamp of the last update, in ISO 8601 form. */
12385
+ updated_at?: string;
12386
+ /** Any additional fields returned by MyAnimeList remain available without narrowing. */
12387
+ [field: string]: unknown;
12388
+ }
11801
12389
 
11802
12390
  /**
11803
12391
  * {@link MyAnimeListAnimeApi} is the anime group exposed by {@link MyAnimeListApi} under `aniLink.mal.anime`.
11804
12392
  *
11805
- * It is the facade boundary for MyAnimeList anime reads; the single `MalAnimeOperation.get | get` method delegates to `MalAnimeOperation` and returns a {@link MalAnime} shaped by {@link MalRequestOptions.fields}.
12393
+ * It is the facade boundary for MyAnimeList anime reads and list-status writes; the `MalAnimeOperation.get | get` method delegates to `MalAnimeOperation` and returns a {@link MalAnime} shaped by {@link MalRequestOptions.fields}, while `updateMyListStatus` and `deleteFromList` cover the authenticated `PATCH` and `DELETE /anime/{id}/my_list_status` endpoints.
11806
12394
  *
11807
12395
  * @see https://myanimelist.net/apiconfig/references/api/v2#tag/anime/operation/anime_anime_id_get
12396
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/user-animelist/operation/anime_anime_id_my_list_status_put
12397
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/user-animelist/operation/anime_anime_id_my_list_status_delete
11808
12398
  */
11809
12399
  interface MyAnimeListAnimeApi {
11810
12400
  /**
@@ -11825,6 +12415,121 @@ interface MyAnimeListAnimeApi {
11825
12415
  * @see https://myanimelist.net/apiconfig/references/api/v2#tag/anime/operation/anime_anime_id_get
11826
12416
  */
11827
12417
  get: (id: number, options?: MalRequestOptions) => Promise<MalAnime>;
12418
+ /**
12419
+ * {@link MyAnimeListAnimeApi.updateMyListStatus} updates the authenticated user's anime list status through `MalAnimeOperation.updateMyListStatus`.
12420
+ *
12421
+ * It is the public facade for `PATCH /anime/{id}/my_list_status` and requires a MAL access token from `MalCredentials.accessToken` via `buildMyAnimeListApi`; send only the {@link MalAnimeListStatusUpdate} fields you want to change, form-encoded as MAL requires.
12422
+ *
12423
+ * @param id - The MyAnimeList anime ID.
12424
+ * @param payload - The list-status fields to update; a {@link MalAnimeListStatusUpdate} of only the fields to change.
12425
+ * @param options - Optional field selection and transport settings; a {@link MalRequestOptions} merged over the instance defaults.
12426
+ * @returns The updated {@link MalAnimeListStatus}.
12427
+ * @throws `AniLinkAuthError` when no MAL access token is configured.
12428
+ * @throws `AniLinkRestError` for a non-success MyAnimeList response.
12429
+ * @throws `AniLinkNetworkError` for timeout, cancellation, or other transport failures.
12430
+ * @example
12431
+ * ```typescript
12432
+ * const api = new AniLink({ mal: { accessToken: "mal-token" } }).mal;
12433
+ * const status = await api.anime.updateMyListStatus(21, {
12434
+ * status: "watching",
12435
+ * num_watched_episodes: 10,
12436
+ * score: 9,
12437
+ * });
12438
+ * ```
12439
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/user-animelist/operation/anime_anime_id_my_list_status_put
12440
+ */
12441
+ updateMyListStatus: (id: number, payload: MalAnimeListStatusUpdate, options?: MalRequestOptions) => Promise<MalAnimeListStatus>;
12442
+ /**
12443
+ * {@link MyAnimeListAnimeApi.deleteFromList} removes an anime from the authenticated user's list through `MalAnimeOperation.deleteFromList`.
12444
+ *
12445
+ * It is the public facade for `DELETE /anime/{id}/my_list_status` and requires a MAL access token from `MalCredentials.accessToken` via `buildMyAnimeListApi`.
12446
+ *
12447
+ * @param id - The MyAnimeList anime ID.
12448
+ * @param options - Optional transport settings; a {@link MalRequestOptions} merged over the instance defaults.
12449
+ * @returns Resolves once the entry is deleted; the response carries no body.
12450
+ * @throws `AniLinkAuthError` when no MAL access token is configured.
12451
+ * @throws `AniLinkRestError` for a non-success MyAnimeList response.
12452
+ * @throws `AniLinkNetworkError` for timeout, cancellation, or other transport failures.
12453
+ * @example
12454
+ * ```typescript
12455
+ * const api = new AniLink({ mal: { accessToken: "mal-token" } }).mal;
12456
+ * await api.anime.deleteFromList(21);
12457
+ * ```
12458
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/user-animelist/operation/anime_anime_id_my_list_status_delete
12459
+ */
12460
+ deleteFromList: (id: number, options?: MalRequestOptions) => Promise<void>;
12461
+ }
12462
+ /**
12463
+ * {@link MyAnimeListMangaApi} is the manga group exposed by {@link MyAnimeListApi} under `aniLink.mal.manga`.
12464
+ *
12465
+ * It is the facade boundary for MyAnimeList manga reads and list-status writes; the {@link MalMangaOperation.get | get} method delegates to `MalMangaOperation` and returns a {@link MalManga} shaped by {@link MalRequestOptions.fields}, while `updateMyListStatus` and `deleteFromList` cover the authenticated `PATCH` and `DELETE /manga/{id}/my_list_status` endpoints.
12466
+ *
12467
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/manga/operation/manga_manga_id_get
12468
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/user-mangalist/operation/manga_manga_id_my_list_status_put
12469
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/user-mangalist/operation/manga_manga_id_my_list_status_delete
12470
+ */
12471
+ interface MyAnimeListMangaApi {
12472
+ /**
12473
+ * {@link MyAnimeListMangaApi.get} gets one manga by its MyAnimeList ID through `MalMangaOperation.get`.
12474
+ *
12475
+ * It is the public facade for the `GET /manga/{id}` endpoint; use {@link MalRequestOptions.fields} to select the response shape and {@link MalRequestOptions} transport settings to override per call.
12476
+ *
12477
+ * @param id - The MyAnimeList manga ID.
12478
+ * @param options - Optional field selection and transport settings; a {@link MalRequestOptions} merged over the instance defaults.
12479
+ * @returns The requested {@link MalManga}.
12480
+ * @throws `AniLinkRestError` for a non-success MyAnimeList response.
12481
+ * @throws `AniLinkNetworkError` for timeout, cancellation, or other transport failures.
12482
+ * @example
12483
+ * ```typescript
12484
+ * const api = new AniLink({ mal: { accessToken: "mal-token" } }).mal;
12485
+ * const manga = await api.manga.get(1, { fields: ["id", "title", "main_picture"] });
12486
+ * ```
12487
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/manga/operation/manga_manga_id_get
12488
+ */
12489
+ get: (id: number, options?: MalRequestOptions) => Promise<MalManga>;
12490
+ /**
12491
+ * {@link MyAnimeListMangaApi.updateMyListStatus} updates the authenticated user's manga list status through `MalMangaOperation.updateMyListStatus`.
12492
+ *
12493
+ * It is the public facade for `PATCH /manga/{id}/my_list_status` and requires a MAL access token from `MalCredentials.accessToken` via `buildMyAnimeListApi`; send only the {@link MalMangaListStatusUpdate} fields you want to change, form-encoded as MAL requires.
12494
+ *
12495
+ * @param id - The MyAnimeList manga ID.
12496
+ * @param payload - The list-status fields to update; a {@link MalMangaListStatusUpdate} of only the fields to change.
12497
+ * @param options - Optional field selection and transport settings; a {@link MalRequestOptions} merged over the instance defaults.
12498
+ * @returns The updated {@link MalMangaListStatus}.
12499
+ * @throws `AniLinkAuthError` when no MAL access token is configured.
12500
+ * @throws `AniLinkRestError` for a non-success MyAnimeList response.
12501
+ * @throws `AniLinkNetworkError` for timeout, cancellation, or other transport failures.
12502
+ * @example
12503
+ * ```typescript
12504
+ * const api = new AniLink({ mal: { accessToken: "mal-token" } }).mal;
12505
+ * const status = await api.manga.updateMyListStatus(1, {
12506
+ * status: "reading",
12507
+ * num_chapters_read: 10,
12508
+ * score: 9,
12509
+ * });
12510
+ * ```
12511
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/user-mangalist/operation/manga_manga_id_my_list_status_put
12512
+ */
12513
+ updateMyListStatus: (id: number, payload: MalMangaListStatusUpdate, options?: MalRequestOptions) => Promise<MalMangaListStatus>;
12514
+ /**
12515
+ * {@link MyAnimeListMangaApi.deleteFromList} removes a manga from the authenticated user's list through `MalMangaOperation.deleteFromList`.
12516
+ *
12517
+ * It is the public facade for `DELETE /manga/{id}/my_list_status` and requires a MAL access token from `MalCredentials.accessToken` via `buildMyAnimeListApi`.
12518
+ *
12519
+ * @param id - The MyAnimeList manga ID.
12520
+ * @param options - Optional transport settings; a {@link MalRequestOptions} merged over the instance defaults.
12521
+ * @returns Resolves once the entry is deleted; the response carries no body.
12522
+ * @throws `AniLinkAuthError` when no MAL access token is configured.
12523
+ * @throws `AniLinkRestError` for a non-success MyAnimeList response.
12524
+ * @throws `AniLinkNetworkError` for timeout, cancellation, or other transport failures.
12525
+ * @example
12526
+ * ```typescript
12527
+ * const api = new AniLink({ mal: { accessToken: "mal-token" } }).mal;
12528
+ * await api.manga.deleteFromList(1);
12529
+ * ```
12530
+ * @see https://myanimelist.net/apiconfig/references/api/v2#tag/user-mangalist/operation/manga_manga_id_my_list_status_delete
12531
+ */
12532
+ deleteFromList: (id: number, options?: MalRequestOptions) => Promise<void>;
11828
12533
  }
11829
12534
  /**
11830
12535
  * {@link MyAnimeListUserApi} is the user group exposed by {@link MyAnimeListApi} under `aniLink.mal.user`.
@@ -11856,26 +12561,19 @@ interface MyAnimeListUserApi {
11856
12561
  /**
11857
12562
  * {@link MyAnimeListApi} is the typed MyAnimeList REST surface exposed by `aniLink.mal`.
11858
12563
  *
11859
- * It composes {@link MyAnimeListAnimeApi} and {@link MyAnimeListUserApi} from `MalAnimeOperation` and `MalUserOperation` via `buildMyAnimeListApi`. Every method accepts {@link MalRequestOptions} and returns {@link MalAnime} or {@link MalUser}; OAuth helpers `buildMalAuthorizationUrl`, `getMalAccessToken`, and `refreshMalAccessToken` supply the token for `MalCredentials`.
12564
+ * It composes {@link MyAnimeListAnimeApi}, {@link MyAnimeListMangaApi}, and {@link MyAnimeListUserApi} from `MalAnimeOperation`, `MalMangaOperation`, and `MalUserOperation` via `buildMyAnimeListApi`. Read methods accept {@link MalRequestOptions} and return {@link MalAnime}, {@link MalManga}, or {@link MalUser}; the anime and manga groups additionally expose `updateMyListStatus` and `deleteFromList` for the authenticated list-status write/delete endpoints. OAuth helpers `buildMalAuthorizationUrl`, `getMalAccessToken`, and `refreshMalAccessToken` supply the token for `MalCredentials`.
11860
12565
  *
11861
12566
  * @see https://myanimelist.net/apiconfig/references/api/v2
11862
12567
  */
11863
12568
  interface MyAnimeListApi {
11864
12569
  /** Anime operations via {@link MyAnimeListAnimeApi} and `MalAnimeOperation`. */
11865
12570
  anime: MyAnimeListAnimeApi;
12571
+ /** Manga operations via {@link MyAnimeListMangaApi} and `MalMangaOperation`. */
12572
+ manga: MyAnimeListMangaApi;
11866
12573
  /** User operations via {@link MyAnimeListUserApi} and `MalUserOperation`. */
11867
12574
  user: MyAnimeListUserApi;
11868
12575
  }
11869
12576
 
11870
- /**
11871
- * Per-provider credential shapes accepted by the {@link AniLink} constructor.
11872
- *
11873
- * Every provider owns its own credentials: AniList authenticates with a
11874
- * bearer token, while REST providers such as MyAnimeList carry their own
11875
- * access-token and PKCE fields. All shapes extend {@link ProviderCredentials}
11876
- * so transport settings stay uniform across providers.
11877
- */
11878
-
11879
12577
  /**
11880
12578
  * Transport settings shared by every provider's slot in an
11881
12579
  * {@link AniLinkCredentials} object. Provider-specific credential types
@@ -11923,7 +12621,10 @@ interface MalCredentials extends ProviderCredentials {
11923
12621
  *
11924
12622
  * Each key targets exactly one provider namespace (`aniLink.anilist`,
11925
12623
  * `aniLink.mal`, …); credentials given under one key are never applied to
11926
- * another provider's requests.
12624
+ * another provider's requests. The optional top-level `onHookError` is a
12625
+ * client-level default applied to every provider slot that does not define
12626
+ * its own, so a single hook-error logger can be wired once instead of
12627
+ * repeated per slot.
11927
12628
  *
11928
12629
  * @see {@link ProviderCredentials}
11929
12630
  */
@@ -11932,6 +12633,14 @@ interface AniLinkCredentials {
11932
12633
  anilist?: AniListCredentials;
11933
12634
  /** Credentials for the MyAnimeList provider surface. */
11934
12635
  mal?: MalCredentials;
12636
+ /**
12637
+ * Client-level default for the `onHookError` lifecycle hook, applied to
12638
+ * every provider slot that does not define its own `onHookError`. Lets
12639
+ * consumers route hook failures to a real logger once per client instead
12640
+ * of repeating the wiring on every call or accepting uncorrelated
12641
+ * `console.warn` noise.
12642
+ */
12643
+ onHookError?: OnHookErrorHandler;
11935
12644
  }
11936
12645
  /**
11937
12646
  * Normalized authentication and transport settings for one provider slot.
@@ -12262,7 +12971,7 @@ declare const getMalTokenExpiry: (response: MalTokenResponse, now?: number) => D
12262
12971
  /**
12263
12972
  * {@link buildMyAnimeListApi} is the wiring helper that builds the {@link MyAnimeListApi} from provider-owned {@link MalCredentials}.
12264
12973
  *
12265
- * It resolves credentials through {@link resolveMalCredentials} and composes {@link MalAnimeOperation} and {@link MalUserOperation} into the {@link MyAnimeListApi} facade exposed as `aniLink.mal`. Transport settings from {@link MalCredentials} flow to `MalRequestOptions` without leaking between providers.
12974
+ * It resolves credentials through {@link resolveMalCredentials} and composes {@link MalAnimeOperation}, {@link MalMangaOperation}, and {@link MalUserOperation} into the {@link MyAnimeListApi} facade exposed as `aniLink.mal`. Transport settings from {@link MalCredentials} flow to `MalRequestOptions` without leaking between providers.
12266
12975
  *
12267
12976
  * @param credentials - MAL access and OAuth credentials plus transport settings; a {@link MalCredentials} slot.
12268
12977
  * @returns The composed {@link MyAnimeListApi} surface.
@@ -12325,5 +13034,5 @@ declare class AniLink {
12325
13034
  constructor(authToken?: string | AniLinkCredentials, options?: AniLinkOptions);
12326
13035
  }
12327
13036
 
12328
- export { ANILIST_AUTHORIZE_URL, ANILIST_TOKEN_URL, AniLink, AniLinkApiError, AniLinkAuthError, AniLinkError, AniLinkErrorCodes, AniLinkGraphQLError, AniLinkNetworkError, AniLinkRestError, AniLinkValidationError, MAL_API_BASE_URL, MAL_API_REFERENCE, MAL_AUTHORIZE_URL, MAL_TOKEN_URL, buildAuthorizationUrl, buildMalAuthorizationUrl, buildMyAnimeListApi, buildProviderClients, getAccessToken, getMalAccessToken, getMalTokenExpiry, getTokenExpiry, paginate, paginateChunks, paginatePages, refreshAccessToken, refreshMalAccessToken };
12329
- export type { AniLinkCredentials, AniLinkErrorCode, AniLinkOptions, AniListApi, AniListCredentials, AniListTokenResponse, ChunkPaginateOptions, ChunkPaginateResult, MalAnime as M, MalAuthorizationCodeRequest, MalCredentials, MalRefreshTokenRequest, MalTokenResponse, MyAnimeListApi, PaginateOptions, PaginateResult, ProviderClients, ProviderCredentials, ProviderFactory, ProviderId, RequestOptions as R, RateLimitInfo, RequestAuth, RequestAuthInput, ResolvedProviderCredentials, MalPicture as a, MalRequestOptions as b, MalUser as c, MyAnimeListAnimeApi as d, MyAnimeListUserApi as e };
13037
+ export { ANILIST_AUTHORIZE_URL, ANILIST_TOKEN_URL, AniLink, AniLinkApiError, AniLinkAuthError, AniLinkError, AniLinkErrorCodes, AniLinkGraphQLError, AniLinkNetworkError, AniLinkRestError, AniLinkValidationError, MAL_API_BASE_URL, MAL_API_REFERENCE, MAL_AUTHORIZE_URL, MAL_TOKEN_URL, ResponseCache, buildAuthorizationUrl, buildMalAuthorizationUrl, buildMyAnimeListApi, buildProviderClients, destroyCachedAgents, getAccessToken, getMalAccessToken, getMalTokenExpiry, getTokenExpiry, paginate, paginateChunks, paginatePages, refreshAccessToken, refreshMalAccessToken };
13038
+ export type { AniLinkCredentials, AniLinkErrorCode, AniLinkOptions, AniListApi, AniListCredentials, AniListTokenResponse, ChunkPaginateOptions, ChunkPaginateResult, CircuitOpenContext, MalAnime as M, MalAuthorizationCodeRequest, MalCredentials, MalRefreshTokenRequest, MalTokenResponse, MyAnimeListApi, OnCircuitCloseHandler, OnCircuitOpenHandler, OnHookErrorHandler, OnPaceHandler, OnResponseHandler, PaginateOptions, PaginateResult, ProviderClients, ProviderCredentials, ProviderFactory, ProviderId, RateLimitInfo, RequestAuth, RequestAuthInput, RequestContext, RequestErrorContext, RequestOptions, ResolvedProviderCredentials, ResponseCacheOptions, MalAnimeListStatus as a, MalAnimeListStatusUpdate as b, MalAnimeListStatusValue as c, MalManga as d, MalMangaListStatus as e, MalMangaListStatusUpdate as f, MalMangaListStatusValue as g, MalPicture as h, MalRequestOptions as i, MalUser as j, MyAnimeListAnimeApi as k, MyAnimeListMangaApi as l, MyAnimeListUserApi as m };