@carddex/sdk 0.1.0 → 0.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/index.d.ts CHANGED
@@ -1,3 +1,583 @@
1
- export { CardDexClient } from './client.js';
2
- export type { Card, CardWithRelations, CardAttack, CardAbility, CardWeakness, CardResistance, CardImage, CardPrice, CardVariant, CardMeta, Set, PaginatedResponse, PaginationMeta, CardListParams, CardDexClientOptions, WebhookSubscription, } from './types.js';
3
- //# sourceMappingURL=index.d.ts.map
1
+ type QueryValue = string | number | boolean | undefined | null | readonly (string | number)[];
2
+ type QueryParams = Record<string, QueryValue>;
3
+ interface RetryOptions {
4
+ /** Max retry attempts on 429. Default 2. */
5
+ maxRetries?: number;
6
+ /**
7
+ * A computed `Retry-After` above this many seconds is never honoured — the
8
+ * request fails immediately instead of sleeping (this is what keeps a
9
+ * daily-quota 429, whose `Retry-After` can be most of a day, from blocking
10
+ * for hours). Default 60, matching the per-minute limiter's own
11
+ * `Retry-After: 60`.
12
+ */
13
+ maxWaitSeconds?: number;
14
+ }
15
+ interface HttpClientOptions {
16
+ baseUrl: string;
17
+ apiKey?: string;
18
+ fetch: typeof fetch;
19
+ /** `false` (default) disables retries; `true` enables them with the defaults below. */
20
+ retry?: boolean | RetryOptions;
21
+ }
22
+ /**
23
+ * Minimal fetch wrapper: builds URLs, attaches auth, parses JSON, and turns
24
+ * non-2xx responses into `CardDexError`. No dependency beyond global `fetch`.
25
+ */
26
+ declare class HttpClient {
27
+ private readonly baseUrl;
28
+ private readonly apiKey;
29
+ private readonly fetchImpl;
30
+ private readonly retryConfig;
31
+ constructor(options: HttpClientOptions);
32
+ get<T>(path: string, query?: QueryParams, signal?: AbortSignal): Promise<T>;
33
+ post<T>(path: string, body?: unknown, signal?: AbortSignal): Promise<T>;
34
+ private request;
35
+ }
36
+
37
+ /**
38
+ * Domain types for CardDex API responses.
39
+ *
40
+ * The OpenAPI spec (`openapi.json` in this package, generated from
41
+ * `https://api.carddex.dev/openapi.json`) currently documents paths,
42
+ * parameters and status codes but not response body schemas — every
43
+ * `responses[status]` is a bare `{ description }`. `src/generated/openapi.d.ts`
44
+ * is generated straight from that spec and is honest about the gap: response
45
+ * bodies come back typed as `unknown`.
46
+ *
47
+ * These interfaces fill that gap by hand, mirroring the API's own internal
48
+ * row shapes (`apps/carddex-api/src/types/index.ts` /
49
+ * `packages/shared/src/types/*.ts` in the monorepo this SDK ships from) as of
50
+ * 2026-09-27. They are the best available typing today; once the API adds
51
+ * `content.schema` to its OpenAPI responses, this file should be regenerated
52
+ * instead of maintained by hand.
53
+ */
54
+ interface CardDexSet {
55
+ id: string;
56
+ name: string;
57
+ series: string | null;
58
+ release_date: string | null;
59
+ official_cards: number | null;
60
+ total_cards: number | null;
61
+ logo_url: string | null;
62
+ symbol_url: string | null;
63
+ set_code: string | null;
64
+ created_at: string;
65
+ updated_at: string;
66
+ }
67
+ interface CardAttack {
68
+ id: number;
69
+ card_id: string;
70
+ name: string;
71
+ cost: string[] | null;
72
+ damage: string | null;
73
+ text: string | null;
74
+ sort_order: number | null;
75
+ }
76
+ interface CardAbility {
77
+ id: number;
78
+ card_id: string;
79
+ name: string;
80
+ text: string | null;
81
+ type: string | null;
82
+ }
83
+ interface CardWeakness {
84
+ id: number;
85
+ card_id: string;
86
+ type: string;
87
+ value: string;
88
+ }
89
+ interface CardResistance {
90
+ id: number;
91
+ card_id: string;
92
+ type: string;
93
+ value: string;
94
+ }
95
+ interface CardImage {
96
+ id: number;
97
+ card_id: string;
98
+ language: string;
99
+ small_url: string | null;
100
+ large_url: string | null;
101
+ }
102
+ /** One price guide's currency and figures. `source` is `'cardmarket' | 'tcgplayer'` in practice. */
103
+ interface CardPrice {
104
+ id: number;
105
+ card_id: string;
106
+ card_name?: string | null;
107
+ number?: string | null;
108
+ set_id?: string | null;
109
+ rarity?: string | null;
110
+ supertype?: string | null;
111
+ variant_id: string | null;
112
+ source: string;
113
+ currency: string;
114
+ trend_price: number | null;
115
+ avg_price: number | null;
116
+ low_price: number | null;
117
+ avg_1d: number | null;
118
+ avg_7d: number | null;
119
+ avg_30d: number | null;
120
+ price_change_1d: number | null;
121
+ price_change_7d: number | null;
122
+ price_change_30d: number | null;
123
+ recorded_at: string;
124
+ }
125
+ /** A `/v1/prices/bargains` row: a `CardPrice` plus the discount used to rank it. */
126
+ type BargainCardPrice = CardPrice & {
127
+ discount_pct: number;
128
+ };
129
+ interface CardVariant {
130
+ id: string;
131
+ card_id: string;
132
+ variant_type: string;
133
+ edition: string | null;
134
+ rarity: string | null;
135
+ image_url: string | null;
136
+ artist: string | null;
137
+ ball_type: string | null;
138
+ source: string;
139
+ cardmarket_id: number | null;
140
+ cardmarket_url: string | null;
141
+ tcgplayer_id: number | null;
142
+ created_at: string;
143
+ updated_at: string;
144
+ /** `1` on the card's base print, `0` on alternates. See variant-list endpoints. */
145
+ is_base?: number;
146
+ }
147
+ interface Card {
148
+ id: string;
149
+ set_id: string;
150
+ name: string;
151
+ number: string;
152
+ supertype: string;
153
+ subtypes: string[] | null;
154
+ hp: number | null;
155
+ types: string[] | null;
156
+ rarity: string | null;
157
+ artist: string | null;
158
+ regulation_mark: string | null;
159
+ flavor_text: string | null;
160
+ rules: string[] | null;
161
+ evolves_from: string | null;
162
+ evolves_to: string[] | null;
163
+ retreat_cost: number;
164
+ legalities: Record<string, string> | null;
165
+ cardmarket_id: number | null;
166
+ cardmarket_url: string | null;
167
+ tcgplayer_id: number | null;
168
+ version_code: string | null;
169
+ created_at: string;
170
+ updated_at: string;
171
+ }
172
+ /** A `Card` with the relations requested via `include=`. Every field here is optional and only present when asked for. */
173
+ interface CardWithRelations extends Card {
174
+ attacks?: CardAttack[];
175
+ abilities?: CardAbility[];
176
+ weaknesses?: CardWeakness[];
177
+ resistances?: CardResistance[];
178
+ images?: CardImage[];
179
+ prices?: CardPrice[];
180
+ variants?: CardVariant[];
181
+ set?: CardDexSet;
182
+ }
183
+ /** The 2 previous / 2 next card ids within a set, from `/v1/sets/{id}/cards/{cardId}/neighbors`. */
184
+ interface CardNeighbors {
185
+ prev_prev: string | null;
186
+ prev: string | null;
187
+ next: string | null;
188
+ next_next: string | null;
189
+ }
190
+ /** Known `sealed_products.product_type` values. The column has no CHECK constraint, so treat this as open — expect strings not (yet) listed here. */
191
+ type SealedProductType = 'booster_box' | 'booster_bundle' | 'elite_trainer_box' | 'case' | 'collection' | 'premium_collection' | 'tin' | 'mini_tin' | 'blister' | 'deck' | 'trainer_kit' | 'build_and_battle' | 'other';
192
+ interface SealedLatestPrice {
193
+ source: string;
194
+ currency: string;
195
+ trend: number | null;
196
+ avg: number | null;
197
+ low: number | null;
198
+ avg_1d: number | null;
199
+ avg_7d: number | null;
200
+ avg_30d: number | null;
201
+ price_change_1d: number | null;
202
+ price_change_7d: number | null;
203
+ price_change_30d: number | null;
204
+ recorded_at: string;
205
+ }
206
+ interface SealedProduct {
207
+ id: string;
208
+ set_id: string | null;
209
+ name: string;
210
+ product_type: string;
211
+ cardmarket_id: number | null;
212
+ cardmarket_category_id: number | null;
213
+ cardmarket_expansion: string | null;
214
+ image_url: string | null;
215
+ source_image_url: string | null;
216
+ created_at: string;
217
+ updated_at: string;
218
+ /** The newest price row, or `null` if the product has never been priced. */
219
+ latest_price?: SealedLatestPrice | null;
220
+ }
221
+ /** A row of sealed price history. Mirrors `CardPrice` minus `variant_id`. */
222
+ interface SealedPrice {
223
+ id: number;
224
+ sealed_product_id: string;
225
+ source: string;
226
+ currency: string;
227
+ trend_price: number | null;
228
+ avg_price: number | null;
229
+ low_price: number | null;
230
+ avg_1d: number | null;
231
+ avg_7d: number | null;
232
+ avg_30d: number | null;
233
+ price_change_1d: number | null;
234
+ price_change_7d: number | null;
235
+ price_change_30d: number | null;
236
+ recorded_at: string;
237
+ }
238
+ interface PaginationMeta {
239
+ total: number;
240
+ page: number;
241
+ pageSize: number;
242
+ totalPages: number;
243
+ }
244
+ interface PaginatedResponse<T> {
245
+ data: T[];
246
+ meta: PaginationMeta;
247
+ }
248
+ interface SingleResponse<T> {
249
+ data: T;
250
+ }
251
+ /**
252
+ * The API's error body, present on every non-2xx JSON response.
253
+ *
254
+ * `docs.astro` shows `code: "NOT_FOUND"` as an example, but
255
+ * `apps/carddex-api/src/middleware/errorHandler.ts` actually writes the HTTP
256
+ * status number into `code` (`{ error: { code: err.status, message } }`), and
257
+ * `packages/shared`'s own `ErrorResponse` type agrees (`code: number`). This
258
+ * SDK follows the real runtime shape, not the docs example — see the "spec
259
+ * gaps" note in this package's README.
260
+ */
261
+ interface ApiErrorBody {
262
+ error: {
263
+ code: number;
264
+ message: string;
265
+ };
266
+ }
267
+ interface UsageRecentRequest {
268
+ endpoint: string;
269
+ status_code: number | null;
270
+ response_time_ms: number | null;
271
+ created_at: string;
272
+ }
273
+ /** Response of `GET /v1/auth/usage` for the calling API key. */
274
+ interface UsageResponse {
275
+ tier: string;
276
+ /** Requests per minute allowed for the tier; `null` for admin keys. */
277
+ rate_limit: number | null;
278
+ /** Requests per UTC day allowed for the tier; `null` when uncapped. */
279
+ daily_limit: number | null;
280
+ requests_today: number;
281
+ total_requests: number;
282
+ /** Last 100 requests, newest first. */
283
+ recent: UsageRecentRequest[];
284
+ }
285
+ /** Response of `POST /v1/auth/register`. */
286
+ interface RegisterResponse {
287
+ api_key: string;
288
+ tier: string;
289
+ rate_limit: number;
290
+ message: string;
291
+ }
292
+ /** Response of `GET /v1/health`. */
293
+ interface HealthResponse {
294
+ status: 'ok' | 'degraded';
295
+ [key: string]: unknown;
296
+ }
297
+
298
+ declare class AuthResource {
299
+ private readonly http;
300
+ constructor(http: HttpClient);
301
+ /**
302
+ * `POST /v1/auth/register` — claim a free API key. The key is returned
303
+ * exactly once, so store it immediately. A lost key can be replaced by signing
304
+ * in at https://carddex.dev/account (create, rotate or revoke keys there).
305
+ */
306
+ register(email: string, name?: string): Promise<RegisterResponse>;
307
+ /** `GET /v1/auth/usage` — usage stats for the API key this client was constructed with. Requires an `apiKey`. */
308
+ usage(): Promise<UsageResponse>;
309
+ }
310
+
311
+ /**
312
+ * Request parameter types, mirroring the query parameters declared in
313
+ * `OPENAPI_SPEC` (`apps/carddex-api/src/routes/docs.ts`) in the monorepo.
314
+ */
315
+ /** A single price guide, or several comma-joined to get each one's own labelled series (display endpoints only). */
316
+ type CardPriceSource = 'cardmarket' | 'tcgplayer' | (string & {});
317
+ /** Ranking endpoints (`/prices/top`, `/trends`, `/bargains`) sort by one guide's price, so only one is accepted. */
318
+ type CardPriceSourceOne = 'cardmarket' | 'tcgplayer';
319
+ /** Sealed products are priced by Cardmarket only. */
320
+ type SealedPriceSource = 'cardmarket';
321
+ type CardSortField = 'name' | 'hp' | 'number' | 'rarity' | 'set' | 'artist' | 'release_date';
322
+ type CardInclude = 'attacks' | 'abilities' | 'weaknesses' | 'resistances' | 'images' | 'prices' | 'variants';
323
+ type CardListParams = {
324
+ name?: string;
325
+ q?: string;
326
+ set?: string;
327
+ type?: string;
328
+ rarity?: string;
329
+ supertype?: string;
330
+ hp_gte?: number;
331
+ hp_lte?: number;
332
+ artist?: string;
333
+ /** The catalogue is English-only for now; anything else is a 400. Defaults to `en`. */
334
+ lang?: 'en';
335
+ page?: number;
336
+ /** Max 250. */
337
+ pageSize?: number;
338
+ sort?: CardSortField;
339
+ order?: 'asc' | 'desc';
340
+ /** One or more of `CardInclude`, comma-separated or as an array. */
341
+ include?: CardInclude | CardInclude[];
342
+ /** One or more price guides — an array asks for each guide's own row. */
343
+ source?: CardPriceSource | CardPriceSource[];
344
+ };
345
+ type CardGetParams = {
346
+ include?: CardInclude | CardInclude[];
347
+ source?: CardPriceSource | CardPriceSource[];
348
+ };
349
+ type CardPricesParams = {
350
+ /** Price this print instead of the base card. */
351
+ variant_id?: string;
352
+ source?: CardPriceSource | CardPriceSource[];
353
+ };
354
+ type CardPriceHistoryParams = CardPricesParams & {
355
+ /** Window length in days, counted back from today. Defaults to 90, capped at 365. */
356
+ days?: number;
357
+ };
358
+ type SetCardsParams = {
359
+ page?: number;
360
+ pageSize?: number;
361
+ };
362
+ type SealedListParams = {
363
+ set_id?: string;
364
+ type?: string;
365
+ q?: string;
366
+ page?: number;
367
+ /** Max 250. */
368
+ pageSize?: number;
369
+ source?: SealedPriceSource;
370
+ };
371
+ type SealedPriceHistoryParams = {
372
+ /** Window length in days. Defaults to 90, capped at 365. */
373
+ days?: number;
374
+ source?: SealedPriceSource;
375
+ };
376
+ type BulkPricesParams = {
377
+ /** Card ids, up to 100. */
378
+ ids?: string[];
379
+ /** Print (variant) ids, up to 100. At least one of `ids`/`variants` is required. */
380
+ variants?: string[];
381
+ source?: CardPriceSource | CardPriceSource[];
382
+ };
383
+ type RankingParams = {
384
+ limit?: number;
385
+ offset?: number;
386
+ /** Narrow to one CardDex set id. */
387
+ set?: string;
388
+ source?: CardPriceSourceOne;
389
+ };
390
+ type TrendsParams = RankingParams & {
391
+ direction?: 'up' | 'down';
392
+ };
393
+ type BargainsParams = RankingParams & {
394
+ mode?: 'below-average' | 'cheapest';
395
+ minPrice?: number;
396
+ };
397
+ type PriceHistoryParams = {
398
+ days?: number;
399
+ /** Print (variant) id; defaults to the base card. */
400
+ variant?: string;
401
+ source?: CardPriceSource | CardPriceSource[];
402
+ };
403
+
404
+ declare class CardsResource {
405
+ private readonly http;
406
+ constructor(http: HttpClient);
407
+ /** `GET /v1/cards` — list, search, filter and sort cards. */
408
+ list(params?: CardListParams): Promise<PaginatedResponse<Card>>;
409
+ /**
410
+ * Iterates every card matching `params` across all pages, fetching pages
411
+ * lazily as you consume them.
412
+ *
413
+ * @example
414
+ * ```ts
415
+ * for await (const card of client.cards.listAll({ set: 'sv06' })) { ... }
416
+ * ```
417
+ */
418
+ listAll(params?: Omit<CardListParams, 'page'>): AsyncGenerator<Card, void, void>;
419
+ /** `GET /v1/cards/random` */
420
+ random(): Promise<CardWithRelations>;
421
+ /** `GET /v1/cards/{id}` */
422
+ get(id: string, params?: CardGetParams): Promise<CardWithRelations>;
423
+ /** `GET /v1/cards/{id}/prices` — the latest price row(s) for a card. */
424
+ prices(id: string, params?: CardPricesParams): Promise<CardPrice[]>;
425
+ /** `GET /v1/cards/{id}/prices/history` — one row per day per price guide, oldest first. */
426
+ priceHistory(id: string, params?: CardPriceHistoryParams): Promise<CardPrice[]>;
427
+ }
428
+
429
+ declare class PricesResource {
430
+ private readonly http;
431
+ constructor(http: HttpClient);
432
+ /**
433
+ * `GET /v1/prices` — latest price rows for up to 100 card ids (and/or up
434
+ * to 100 print/variant ids) in one request. Keyed by the id you asked for;
435
+ * an id with no price data maps to `[]`.
436
+ */
437
+ bulk(params: BulkPricesParams): Promise<Record<string, CardPrice[]>>;
438
+ /** `GET /v1/prices/top` — highest-valued cards. */
439
+ top(params?: RankingParams): Promise<CardPrice[]>;
440
+ /** `GET /v1/prices/trends` — biggest movers against the card's own rolling average. */
441
+ trends(params?: TrendsParams): Promise<CardPrice[]>;
442
+ /** `GET /v1/prices/bargains` — cards trading below a reference price, best discount first. */
443
+ bargains(params?: BargainsParams): Promise<BargainCardPrice[]>;
444
+ /** `GET /v1/prices/{cardId}/history` — one row per day per guide, oldest first. */
445
+ history(cardId: string, params?: PriceHistoryParams): Promise<CardPrice[]>;
446
+ }
447
+
448
+ declare class SealedResource {
449
+ private readonly http;
450
+ constructor(http: HttpClient);
451
+ /** `GET /v1/sealed` — list sealed products with their latest price. */
452
+ list(params?: SealedListParams): Promise<PaginatedResponse<SealedProduct>>;
453
+ /** Iterates every sealed product matching `params` across all pages. */
454
+ listAll(params?: Omit<SealedListParams, 'page'>): AsyncGenerator<SealedProduct, void, void>;
455
+ /** `GET /v1/sealed/{id}` */
456
+ get(id: string, params?: {
457
+ source?: SealedListParams['source'];
458
+ }): Promise<SealedProduct>;
459
+ /** `GET /v1/sealed/{id}/prices` — one row per synced day, oldest first. */
460
+ prices(id: string, params?: SealedPriceHistoryParams): Promise<SealedPrice[]>;
461
+ }
462
+
463
+ declare class SetsResource {
464
+ private readonly http;
465
+ constructor(http: HttpClient);
466
+ /** `GET /v1/sets` — every set. */
467
+ list(): Promise<CardDexSet[]>;
468
+ /** `GET /v1/sets/{id}` */
469
+ get(id: string): Promise<CardDexSet>;
470
+ /** `GET /v1/sets/{id}/cards` */
471
+ cards(id: string, params?: SetCardsParams): Promise<PaginatedResponse<Card>>;
472
+ /** Iterates every card in a set across all pages. */
473
+ cardsAll(id: string, params?: Omit<SetCardsParams, 'page'>): AsyncGenerator<Card, void, void>;
474
+ /** `GET /v1/sets/{id}/cards/{cardId}/neighbors` — the 2 previous / 2 next card ids. */
475
+ neighbors(setId: string, cardId: string): Promise<CardNeighbors>;
476
+ /** `GET /v1/sets/{id}/sealed` — sealed products attached to a set, each with its latest price. */
477
+ sealed(id: string, params?: {
478
+ source?: SealedPriceSource;
479
+ }): Promise<SealedProduct[]>;
480
+ }
481
+
482
+ interface CardDexOptions {
483
+ /**
484
+ * A `pk_live_...` key from `POST /v1/auth/register`. Omit it to call the
485
+ * API anonymously — CardDex allows this at a lower rate (30 req/min,
486
+ * 5,000 req/day per IP), specifically so a browser can call it without a
487
+ * key. **Never ship a real API key in public frontend code**: it would be
488
+ * readable by anyone who opens dev tools and shared by every visitor to
489
+ * your site. Proxy through your own backend instead if you need the
490
+ * higher, keyed limits from a browser context.
491
+ */
492
+ apiKey?: string;
493
+ /** Defaults to `https://api.carddex.dev`. Override for a local/staging API or a CORS proxy. */
494
+ baseUrl?: string;
495
+ /** Defaults to the global `fetch`. Override to inject a custom implementation (proxies, logging, tests). */
496
+ fetch?: typeof fetch;
497
+ /**
498
+ * Automatic retry on `429`, honouring `Retry-After`. **Off by default.**
499
+ * Pass `true` for the defaults (up to 2 retries, never waiting more than
500
+ * 60s), or an object to tune them. A `Retry-After` longer than
501
+ * `maxWaitSeconds` — typically the daily-quota reset, which can be most of
502
+ * a day away — is never honoured; the request fails immediately instead.
503
+ */
504
+ retry?: boolean | RetryOptions;
505
+ }
506
+ /**
507
+ * CardDex API client.
508
+ *
509
+ * ```ts
510
+ * import { CardDex } from '@carddex/sdk';
511
+ *
512
+ * const client = new CardDex({ apiKey: process.env.CARDDEX_API_KEY });
513
+ * const { data } = await client.cards.list({ name: 'Charizard' });
514
+ * ```
515
+ */
516
+ declare class CardDex {
517
+ readonly cards: CardsResource;
518
+ readonly sets: SetsResource;
519
+ readonly sealed: SealedResource;
520
+ readonly prices: PricesResource;
521
+ readonly auth: AuthResource;
522
+ private readonly http;
523
+ constructor(options?: CardDexOptions);
524
+ /** `GET /v1/auth/usage` — shorthand for `client.auth.usage()`. Requires an `apiKey`. */
525
+ usage(): Promise<UsageResponse>;
526
+ /** `GET /v1/health` — API health, price freshness, and cron status. */
527
+ health(): Promise<HealthResponse>;
528
+ }
529
+
530
+ /** Rate-limit info parsed from response headers, when present. */
531
+ interface RateLimitInfo {
532
+ /** `X-RateLimit-Limit`: requests allowed per minute. */
533
+ limit: number | null;
534
+ /** `X-RateLimit-Daily-Limit`: requests allowed per UTC day, or `null` when the tier is uncapped. */
535
+ dailyLimit: number | null;
536
+ /** `X-RateLimit-Daily-Remaining`: approximate, can lag by about a minute. `null` when the API couldn't compute it. */
537
+ dailyRemaining: number | null;
538
+ }
539
+ /**
540
+ * Thrown for any non-2xx response, and for network/parse failures the fetch
541
+ * layer can't attribute to the API itself.
542
+ */
543
+ declare class CardDexError extends Error {
544
+ /** HTTP status code. `0` for a request that never got a response (network failure, abort). */
545
+ readonly status: number;
546
+ /**
547
+ * The API's own `error.code`. For a response the API actually produced,
548
+ * this is the same number as `status` (see the note on `ApiErrorBody` in
549
+ * `types.ts`) — kept as its own field because a transport-level failure
550
+ * (no response at all) sets it to a string like `NETWORK_ERROR` instead.
551
+ */
552
+ readonly code: number | string;
553
+ /** Seconds to wait before retrying, parsed from `Retry-After` on a 429. `null` otherwise. */
554
+ readonly retryAfter: number | null;
555
+ /** Rate-limit headers on the response, when there was one. */
556
+ readonly rateLimit: RateLimitInfo | null;
557
+ constructor(message: string, options: {
558
+ status: number;
559
+ code: number | string;
560
+ retryAfter?: number | null;
561
+ rateLimit?: RateLimitInfo | null;
562
+ cause?: unknown;
563
+ });
564
+ /** Whether this is a 429 (either the per-minute or the daily cap). */
565
+ get isRateLimited(): boolean;
566
+ static fromResponse(response: Response): Promise<CardDexError>;
567
+ static network(cause: unknown): CardDexError;
568
+ }
569
+
570
+ /**
571
+ * Turns a page-fetching function into an async iterator over every item,
572
+ * fetching the next page lazily as the caller consumes items.
573
+ *
574
+ * @example
575
+ * ```ts
576
+ * for await (const card of paginate((page) => client.cards.list({ set: 'sv06', page }))) {
577
+ * console.log(card.name);
578
+ * }
579
+ * ```
580
+ */
581
+ declare function paginate<T>(fetchPage: (page: number) => Promise<PaginatedResponse<T>>, startPage?: number): AsyncGenerator<T, void, void>;
582
+
583
+ export { type ApiErrorBody, type BargainCardPrice, type BargainsParams, type BulkPricesParams, type Card, type CardAbility, type CardAttack, CardDex, CardDexError, type CardDexOptions, type CardDexSet, type CardGetParams, type CardImage, type CardInclude, type CardListParams, type CardNeighbors, type CardPrice, type CardPriceHistoryParams, type CardPriceSource, type CardPriceSourceOne, type CardPricesParams, type CardResistance, type CardSortField, type CardVariant, type CardWeakness, type CardWithRelations, type HealthResponse, type PaginatedResponse, type PaginationMeta, type PriceHistoryParams, type RankingParams, type RateLimitInfo, type RegisterResponse, type RetryOptions, type SealedLatestPrice, type SealedListParams, type SealedPrice, type SealedPriceHistoryParams, type SealedPriceSource, type SealedProduct, type SealedProductType, type SetCardsParams, type SingleResponse, type TrendsParams, type UsageRecentRequest, type UsageResponse, paginate };