scryfall-api 0.0.0-beta-20261103181737

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021-2026 MarioMH
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,100 @@
1
+ ![banner.png](.idea%2Fbanner.png)
2
+
3
+ <h1 align="center">
4
+ scryfall-api
5
+ </h1>
6
+
7
+ <p align="center">
8
+ A Javascript library for <a href='https://scryfall.com/docs/api' target='_blank'>scryfall.com</a> written in Typescript.
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/scryfall-api" rel="nofollow">
13
+ <img src="https://img.shields.io/npm/v/scryfall-api?style=flat-square" alt="npm" style="max-width: 100%;">
14
+ </a>
15
+ <a href="https://github.com/MarioMH8/scryfall-api">
16
+ <img src="https://img.shields.io/github/issues/mariomh8/scryfall-api?style=flat-square" alt="GitHub issues" style="max-width: 100%;">
17
+ </a>
18
+ </p>
19
+
20
+ ## Table of Contents
21
+
22
+ - [Installation](#installation)
23
+ - [Documentation](#documentation)
24
+ - [Contributing](#contributing)
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ npm install --save scryfall-api
30
+ ```
31
+
32
+ **Using bun**
33
+
34
+ ```bash
35
+ bun add scryfall-api
36
+ ```
37
+
38
+ ## Documentation
39
+
40
+ In the documentation below, requiring the package is assumed.
41
+
42
+ ```ts
43
+ import scryfall from 'scryfall-api';
44
+
45
+ scryfall.Cards.byName('Black Lotus').then(console.log);
46
+ ```
47
+
48
+ **With CommonJS**
49
+
50
+ ```js
51
+ const scryfall = require('scryfall-api');
52
+
53
+ scryfall.Cards.byName('Black Lotus').then(console.log);
54
+ ```
55
+
56
+ **If you only need Cards**
57
+
58
+ ```ts
59
+ import { Cards } from 'scryfall-api';
60
+
61
+ Cards.byName('Black Lotus').then(console.log);
62
+ ```
63
+
64
+ Link to [full documentation.](./DOCUMENTATION.md)
65
+
66
+ ## Contributing
67
+
68
+ This project uses [Bun](https://bun.sh) as a runtime, test runner and bundler.
69
+
70
+ Thanks for wanting to help out! Here's the setup you'll have to do:
71
+
72
+ Clone the project
73
+
74
+ ```bash
75
+ git clone git@github.com:MarioMH8/scryfall-api.git
76
+ ```
77
+
78
+ Go to the project directory
79
+
80
+ ```bash
81
+ cd scryfall-api
82
+ ```
83
+
84
+ Install dependencies
85
+
86
+ ```bash
87
+ bun install
88
+ ```
89
+
90
+ Compile the project
91
+
92
+ ```bash
93
+ bun run build
94
+ ```
95
+
96
+ You can read the full [contribution](./CONTRIBUTING.md) guidelines.
97
+
98
+ ## MIT License
99
+
100
+ [Copyright 2021-2026 MarioMH](./LICENSE)
@@ -0,0 +1,447 @@
1
+ type TOrArrayOfT<T> = T | T[];
2
+ /**
3
+ * Type definition for Nullable.
4
+ * @type {T | null | undefined} The type can be T, null, or undefined.
5
+ * @template T The type of the value that can be null or undefined.
6
+ */
7
+ type Nullable<T> = null | T | undefined;
8
+ type ParameterValue = boolean | number | string | undefined;
9
+ type FetcherParameters = Record<string, ParameterValue>;
10
+ type TFetcher = <TData>(apiPath: TOrArrayOfT<number | string | undefined>, parameters?: FetcherParameters, body?: object) => Promise<TData | undefined>;
11
+ type QueryValue = boolean | number | string | undefined;
12
+ interface PageQuery {
13
+ [key: string]: QueryValue;
14
+ page: number;
15
+ }
16
+ declare class MagicPageResult<T> {
17
+ #private;
18
+ private readonly apiPath;
19
+ private readonly query;
20
+ private readonly fetcher;
21
+ constructor(apiPath: string, query: PageQuery, fetcher?: TFetcher);
22
+ get count(): number;
23
+ get hasMore(): boolean;
24
+ all(): Promise<T[]>;
25
+ get(limit: number): Promise<T[]>;
26
+ next(): Promise<T[]>;
27
+ page(page: number): Promise<T[]>;
28
+ private setNextPage;
29
+ }
30
+ interface CardIdentifierId {
31
+ id: string;
32
+ }
33
+ interface CardIdentifierIllustrationId {
34
+ illustration_id: string;
35
+ }
36
+ interface CardIdentifierMtgGoId {
37
+ mtgo_id: number;
38
+ }
39
+ interface CardIdentifierMultiverseId {
40
+ multiverse_id: number;
41
+ }
42
+ interface CardIdentifierNameSet {
43
+ name: string;
44
+ set?: string;
45
+ }
46
+ interface CardIdentifierOracleId {
47
+ oracle_id: string;
48
+ }
49
+ interface CardIdentifierCollectorSet {
50
+ collector_number: string;
51
+ set: string;
52
+ }
53
+ type CardIdentifier = CardIdentifierCollectorSet | CardIdentifierId | CardIdentifierIllustrationId | CardIdentifierMtgGoId | CardIdentifierMultiverseId | CardIdentifierNameSet | CardIdentifierOracleId;
54
+ declare class CardIdentifierApi {
55
+ static byId(id: string): CardIdentifier;
56
+ static byIllustrationId(id: string): CardIdentifier;
57
+ static byMtgoId(id: number): CardIdentifier;
58
+ static byMultiverseId(id: number): CardIdentifier;
59
+ static byName(name: string, set?: string): CardIdentifier;
60
+ static byOracleId(id: string): CardIdentifier;
61
+ static bySet(set: string, collectorNumber: number | string): CardIdentifier;
62
+ }
63
+ type CardLanguage = 'ar' | 'de' | 'en' | 'es' | 'fr' | 'grc' | 'he' | 'it' | 'ja' | 'ko' | 'la' | 'ph' | 'pt' | 'ru' | 'sa' | 'zhs' | 'zht';
64
+ type CardLayout = 'adventure' | 'art_series' | 'augment' | 'battle' | 'case' | 'class' | 'double_faced_token' | 'emblem' | 'flip' | 'host' | 'leveler' | 'meld' | 'modal_dfc' | 'mutate' | 'normal' | 'planar' | 'prototype' | 'reversible_card' | 'saga' | 'scheme' | 'split' | 'token' | 'transform' | 'vanguard';
65
+ interface CardCore {
66
+ arena_id?: Nullable<string>;
67
+ cardmarket_id?: Nullable<number>;
68
+ id: string;
69
+ lang: CardLanguage;
70
+ layout: CardLayout;
71
+ mtgo_foil_id?: Nullable<number>;
72
+ mtgo_id?: Nullable<number>;
73
+ multiverse_ids?: Nullable<number[]>;
74
+ object: 'card';
75
+ oracle_id?: Nullable<string>;
76
+ prints_search_uri: string;
77
+ rulings_uri: string;
78
+ scryfall_uri: string;
79
+ tcgplayer_etched_id?: Nullable<number>;
80
+ tcgplayer_id?: Nullable<number>;
81
+ uri: string;
82
+ }
83
+ type Color = 'B' | 'G' | 'R' | 'U' | 'W';
84
+ interface ManaCost {
85
+ cmc: number;
86
+ colorless: boolean;
87
+ colors: Color[];
88
+ cost: string;
89
+ monocolored: boolean;
90
+ multicolored: boolean;
91
+ object: 'mana_cost';
92
+ }
93
+ interface Symbology {
94
+ appears_in_mana_costs: boolean;
95
+ cmc: number;
96
+ colors: Color[];
97
+ english: string;
98
+ funny: boolean;
99
+ gatherer_alternates?: Nullable<string[]>;
100
+ hybrid: boolean;
101
+ loose_variant?: Nullable<string>;
102
+ mana_value?: Nullable<number>;
103
+ object: 'card_symbol';
104
+ phyrexian: boolean;
105
+ represents_mana: boolean;
106
+ svg_uri?: Nullable<string>;
107
+ symbol: string;
108
+ transposable: boolean;
109
+ }
110
+ declare class SymbologyApi {
111
+ all(): Promise<Symbology[]>;
112
+ parseMana(shorthand: string): Promise<ManaCost>;
113
+ }
114
+ declare const symbology: SymbologyApi;
115
+ interface ImageUris {
116
+ /**
117
+ *Size varies by card.
118
+ */
119
+ art: string;
120
+ /**
121
+ * @deprecated Use `art` instead. Removed on 2027-01-01.
122
+ * @see https://scryfall.com/blog/new-webp-images-jpeg-deprecations-237
123
+ */
124
+ art_crop: string;
125
+ /**
126
+ * @deprecated Use `crop` instead. Removed on 2027-01-01.
127
+ * @see https://scryfall.com/blog/new-webp-images-jpeg-deprecations-237
128
+ */
129
+ border_crop: string;
130
+ /**
131
+ *480 × 680.
132
+ */
133
+ crop: string;
134
+ /**
135
+ *672 × 936.
136
+ */
137
+ display: string;
138
+ /**
139
+ *488 × 680.
140
+ */
141
+ grid: string;
142
+ /**
143
+ *The only remaining JPEG size (488 × 680).
144
+ */
145
+ jpeg: string;
146
+ /**
147
+ * @deprecated Use `display` instead. Removed on 2027-01-01.
148
+ * @see https://scryfall.com/blog/new-webp-images-jpeg-deprecations-237
149
+ */
150
+ large: string;
151
+ /**
152
+ * @deprecated Use `grid` for WebP or `jpeg` for JPEG.
153
+ * @see https://scryfall.com/blog/new-webp-images-jpeg-deprecations-237
154
+ */
155
+ normal: string;
156
+ /**
157
+ *Still available, but hotlinking is not allowed after 2027-01-01.
158
+ */
159
+ png: string;
160
+ /**
161
+ * @deprecated Use `thumb` instead. Removed on 2027-01-01.
162
+ * @see https://scryfall.com/blog/new-webp-images-jpeg-deprecations-237
163
+ */
164
+ small: string;
165
+ /**
166
+ *146 × 204.
167
+ */
168
+ thumb: string;
169
+ }
170
+ type CardComponent = 'combo_piece' | 'meld_part' | 'meld_result' | 'token';
171
+ type Legality = 'banned' | 'legal' | 'not_legal' | 'restricted';
172
+ interface CardFace {
173
+ artist?: Nullable<string>;
174
+ artist_id?: Nullable<string>;
175
+ cmc?: Nullable<number>;
176
+ color_indicator?: Nullable<Color[]>;
177
+ colors?: Nullable<Color[]>;
178
+ defense?: Nullable<string>;
179
+ flavor_text?: Nullable<string>;
180
+ illustration_id?: Nullable<string>;
181
+ image_uris?: Nullable<ImageUris>;
182
+ layout?: Nullable<string>;
183
+ loyalty?: Nullable<string>;
184
+ mana_cost: string;
185
+ name: string;
186
+ object: 'card_face';
187
+ oracle_id?: Nullable<string>;
188
+ oracle_text?: Nullable<string>;
189
+ power?: Nullable<string>;
190
+ printed_name?: Nullable<string>;
191
+ printed_text?: Nullable<string>;
192
+ printed_type_line?: Nullable<string>;
193
+ toughness?: Nullable<string>;
194
+ type_line?: Nullable<string>;
195
+ watermark?: Nullable<string>;
196
+ }
197
+ interface RelatedCard {
198
+ component: CardComponent;
199
+ id: string;
200
+ name: string;
201
+ object: 'related_card';
202
+ type_line: string;
203
+ uri: string;
204
+ }
205
+ interface Legalities {
206
+ alchemy: Legality;
207
+ brawl: Legality;
208
+ commander: Legality;
209
+ duel: Legality;
210
+ explorer: Legality;
211
+ future: Legality;
212
+ gladiator: Legality;
213
+ historic: Legality;
214
+ legacy: Legality;
215
+ modern: Legality;
216
+ oathbreaker: Legality;
217
+ oldschool: Legality;
218
+ pauper: Legality;
219
+ paupercommander: Legality;
220
+ penny: Legality;
221
+ pioneer: Legality;
222
+ predh: Legality;
223
+ premodern: Legality;
224
+ standard: Legality;
225
+ standardbrawl: Legality;
226
+ timeless: Legality;
227
+ vintage: Legality;
228
+ }
229
+ interface GameplayCard {
230
+ all_parts?: Nullable<RelatedCard[]>;
231
+ card_faces?: Nullable<CardFace[]>;
232
+ cmc: number;
233
+ color_identity: Color[];
234
+ color_indicator?: Nullable<Color[]>;
235
+ colors?: Nullable<Color[]>;
236
+ defense?: Nullable<string>;
237
+ edhrec_rank?: Nullable<number>;
238
+ game_changer?: Nullable<boolean>;
239
+ hand_modifier?: Nullable<string>;
240
+ keywords: string[];
241
+ legalities: Legalities;
242
+ life_modifier?: Nullable<string>;
243
+ loyalty?: Nullable<string>;
244
+ mana_cost?: Nullable<string>;
245
+ name: string;
246
+ oracle_text?: Nullable<string>;
247
+ penny_rank?: Nullable<number>;
248
+ power?: Nullable<string>;
249
+ produced_mana?: Nullable<Color[]>;
250
+ reserved: boolean;
251
+ toughness?: Nullable<string>;
252
+ type_line: string;
253
+ }
254
+ type SetType = 'alchemy' | 'archenemy' | 'arsenal' | 'box' | 'commander' | 'core' | 'draft_innovation' | 'duel_deck' | 'expansion' | 'from_the_vault' | 'funny' | 'masterpiece' | 'masters' | 'memorabilia' | 'minigame' | 'planechase' | 'premium_deck' | 'promo' | 'spellbook' | 'starter' | 'token' | 'treasure_chest' | 'vanguard';
255
+ interface Set {
256
+ arena_code?: Nullable<string>;
257
+ block?: Nullable<string>;
258
+ block_code?: Nullable<string>;
259
+ card_count: number;
260
+ code: string;
261
+ digital: boolean;
262
+ foil_only: boolean;
263
+ icon_svg_uri: string;
264
+ id: string;
265
+ mtgo_code?: Nullable<string>;
266
+ name: string;
267
+ nonfoil_only: boolean;
268
+ object: 'set';
269
+ parent_set_code?: Nullable<string>;
270
+ printed_size?: Nullable<number>;
271
+ released_at?: Nullable<Date>;
272
+ scryfall_uri: string;
273
+ search_uri: string;
274
+ set_type: SetType;
275
+ tcgplayer_id?: Nullable<number>;
276
+ uri: string;
277
+ }
278
+ declare class SetApi {
279
+ all(): Promise<Set[]>;
280
+ byCode(code: string): Promise<Set | undefined>;
281
+ byId(id: string): Promise<Set | undefined>;
282
+ byTcgPlayerId(id: number): Promise<Set | undefined>;
283
+ }
284
+ declare const set: SetApi;
285
+ type BorderColor = 'black' | 'borderless' | 'gold' | 'silver' | 'white';
286
+ type Finish = 'etched' | 'foil' | 'nonfoil';
287
+ type Frame = '1993' | '1997' | '2003' | '2015' | 'future';
288
+ type FrameEffect = 'colorshifted' | 'companion' | 'compasslanddfc' | 'convertdfc' | 'devoid' | 'draft' | 'etched' | 'extendedart' | 'fandfc' | 'inverted' | 'legendary' | 'lesson' | 'miracle' | 'mooneldrazidfc' | 'nyxtouched' | 'originpwdfc' | 'shatteredglass' | 'showcase' | 'snow' | 'sunmoondfc' | 'tombstone' | 'upsidedowndfc' | 'waxingandwaningmoondfc';
289
+ type Game = 'arena' | 'mtgo' | 'paper';
290
+ type ImageStatus = 'highres_scan' | 'lowres' | 'missing' | 'placeholder';
291
+ interface Preview {
292
+ previewed_at: Date;
293
+ source: string;
294
+ source_uri: string;
295
+ }
296
+ interface Prices {
297
+ eur?: Nullable<string>;
298
+ eur_foil?: Nullable<string>;
299
+ tix?: Nullable<string>;
300
+ usd?: Nullable<string>;
301
+ usd_etched?: Nullable<string>;
302
+ usd_foil?: Nullable<string>;
303
+ }
304
+ type PromoType = 'arenaleague' | 'buyabox' | 'convention' | 'datestamped' | 'draftweekend' | 'duels' | 'event' | 'fnm' | 'gameday' | 'gateway' | 'giftbox' | 'instore' | 'intropack' | 'judgegift' | 'league' | 'openhouse' | 'ourney' | 'planeswalkerdeck' | 'playerrewards' | 'premiereshop' | 'prerelease' | 'release' | 'setpromo' | 'starterdeck' | 'wizardsplaynetwork';
305
+ interface PurchaseUris {
306
+ [key: string]: Nullable<string>;
307
+ cardhoarder?: Nullable<string>;
308
+ cardmarket?: Nullable<string>;
309
+ tcgplayer?: Nullable<string>;
310
+ }
311
+ type Rarity = 'bonus' | 'common' | 'mythic' | 'rare' | 'special' | 'uncommon';
312
+ interface RelatedUris {
313
+ [key: string]: Nullable<string>;
314
+ edhrec?: Nullable<string>;
315
+ gatherer?: Nullable<string>;
316
+ mtgtop8?: Nullable<string>;
317
+ tcgplayer_decks?: Nullable<string>;
318
+ tcgplayer_infinite_articles?: Nullable<string>;
319
+ tcgplayer_infinite_decks?: Nullable<string>;
320
+ }
321
+ type SecurityStamp = 'acorn' | 'arena' | 'circle' | 'heart' | 'oval' | 'triangle';
322
+ interface CardPrint {
323
+ artist?: Nullable<string>;
324
+ artist_ids?: Nullable<string[]>;
325
+ attraction_lights?: Nullable<number[]>;
326
+ booster: boolean;
327
+ border_color: BorderColor;
328
+ card_back_id: string;
329
+ collector_number: string;
330
+ content_warning?: Nullable<boolean>;
331
+ digital: boolean;
332
+ finishes: Finish[];
333
+ flavor_name?: Nullable<string>;
334
+ flavor_text?: Nullable<string>;
335
+ frame: Frame;
336
+ frame_effects?: Nullable<FrameEffect[]>;
337
+ full_art: boolean;
338
+ games: Game[];
339
+ highres_image: boolean;
340
+ illustration_id?: Nullable<string>;
341
+ image_status: ImageStatus;
342
+ image_uris?: Nullable<ImageUris>;
343
+ oversized: boolean;
344
+ preview: Preview;
345
+ prices: Prices;
346
+ printed_name?: Nullable<string>;
347
+ printed_text?: Nullable<string>;
348
+ printed_type_line?: Nullable<string>;
349
+ promo: boolean;
350
+ promo_types?: Nullable<PromoType[]>;
351
+ purchase_uris?: Nullable<PurchaseUris>;
352
+ rarity: Rarity;
353
+ related_uris: RelatedUris;
354
+ released_at: Date;
355
+ reprint: boolean;
356
+ scryfall_set_uri: string;
357
+ security_stamp?: Nullable<SecurityStamp>;
358
+ set: string;
359
+ set_id: string;
360
+ set_name: string;
361
+ set_search_uri: string;
362
+ set_type: SetType;
363
+ set_uri: string;
364
+ story_spotlight: boolean;
365
+ textless: boolean;
366
+ variation: boolean;
367
+ variation_of?: Nullable<string>;
368
+ watermark?: Nullable<string>;
369
+ }
370
+ type Card = CardCore & CardPrint & GameplayCard;
371
+ type CardSearchUnique = 'art' | 'cards' | 'prints';
372
+ type CardSearchOrder = 'artist' | 'cmc' | 'color' | 'edhrec' | 'eur' | 'name' | 'penny' | 'power' | 'rarity' | 'released' | 'review' | 'set' | 'tix' | 'toughness' | 'usd';
373
+ type CardSearchDirection = 'asc' | 'auto' | 'desc';
374
+ type CardSearchFormat = 'csv' | 'json';
375
+ interface CardSearch {
376
+ dir?: CardSearchDirection;
377
+ format?: CardSearchFormat;
378
+ include_extras?: boolean;
379
+ include_multilingual?: boolean;
380
+ include_variations?: boolean;
381
+ order?: CardSearchOrder;
382
+ page?: number;
383
+ pretty?: boolean;
384
+ unique?: CardSearchUnique;
385
+ }
386
+ declare class CardApi {
387
+ autoCompleteName(name: string): Promise<string[]>;
388
+ byArenaId(id: number): Promise<Card | undefined>;
389
+ byId(id: string): Promise<Card | undefined>;
390
+ byMtgoId(id: number): Promise<Card | undefined>;
391
+ byMultiverseId(id: number): Promise<Card | undefined>;
392
+ byName(name: string, isFuzzySearch?: boolean): Promise<Card | undefined>;
393
+ byName(name: string, set?: string, isFuzzySearch?: boolean): Promise<Card | undefined>;
394
+ bySet(set: string, collectorNumber: number, lang?: string): Promise<Card | undefined>;
395
+ byTcgPlayerId(id: number): Promise<Card | undefined>;
396
+ collection(...identifiers: CardIdentifier[]): Promise<Card[]>;
397
+ random(): Promise<Card>;
398
+ search(query: string, options?: CardSearch | number): MagicPageResult<Card>;
399
+ }
400
+ declare const cards: CardApi;
401
+ declare class CatalogApi {
402
+ artifactTypes(): Promise<string[]>;
403
+ artistNames(): Promise<string[]>;
404
+ cardNames(): Promise<string[]>;
405
+ creatureTypes(): Promise<string[]>;
406
+ enchantmentTypes(): Promise<string[]>;
407
+ landTypes(): Promise<string[]>;
408
+ loyalties(): Promise<string[]>;
409
+ planeswalkerTypes(): Promise<string[]>;
410
+ powers(): Promise<string[]>;
411
+ spellTypes(): Promise<string[]>;
412
+ toughnesses(): Promise<string[]>;
413
+ watermarks(): Promise<string[]>;
414
+ wordBank(): Promise<string[]>;
415
+ }
416
+ declare const catalog: CatalogApi;
417
+ export interface Catalog {
418
+ data: string[];
419
+ object: 'catalog';
420
+ total_values: number;
421
+ uri: string;
422
+ }
423
+ export interface Ruling {
424
+ comment: string;
425
+ object: 'ruling';
426
+ oracle_id: string;
427
+ published_at: Date;
428
+ source: string;
429
+ }
430
+ declare class RulingApi {
431
+ byArenaId(id: number): Promise<Ruling[]>;
432
+ byId(id: string): Promise<Ruling[]>;
433
+ byMtgoId(id: number): Promise<Ruling[]>;
434
+ byMultiverseId(id: number): Promise<Ruling[]>;
435
+ bySet(set: string, collectorNumber: number | string): Promise<Ruling[]>;
436
+ }
437
+ declare const rulings: RulingApi;
438
+ declare class InvalidScryfallArgumentError extends Error {}
439
+ declare class ScryfallError extends Error {
440
+ readonly code: string;
441
+ readonly status: number;
442
+ readonly type?: null | string | undefined;
443
+ readonly warnings?: null | string[] | undefined;
444
+ constructor(code: string, details: string, status: number, type?: null | string | undefined, warnings?: null | string[] | undefined);
445
+ }
446
+ declare class UnknownScryfallError extends Error {}
447
+ export { type BorderColor, type Card, type CardComponent, type CardFace, type CardIdentifier, CardIdentifierApi as CardIdentifierBuilder, type CardIdentifierCollectorSet, type CardIdentifierId, type CardIdentifierIllustrationId, type CardIdentifierMtgGoId, type CardIdentifierMultiverseId, type CardIdentifierNameSet, type CardIdentifierOracleId, type CardLanguage, type CardLayout, type CardSearch, type CardSearchDirection, type CardSearchFormat, type CardSearchOrder, type CardSearchUnique, cards as Cards, catalog as Catalogs, type Color, type Finish, type Frame, type FrameEffect, type Game, type ImageStatus, type ImageUris, InvalidScryfallArgumentError, type Legalities, type Legality, MagicPageResult, type ManaCost, type Preview, type Prices, type PromoType, type PurchaseUris, type Rarity, type RelatedCard, type RelatedUris, rulings as Rulings, ScryfallError, type SecurityStamp, type Set, type SetType, set as Sets, type Symbology, symbology as SymbologyApi, UnknownScryfallError };
@@ -0,0 +1,401 @@
1
+ // src/error/invalid.error.ts
2
+ var InvalidScryfallArgumentError = class extends Error {};
3
+
4
+ // src/error/scryfall.error.ts
5
+ var ScryfallError = class extends Error {
6
+ code;
7
+ status;
8
+ type;
9
+ warnings;
10
+ constructor(code, details, status, type, warnings) {
11
+ super(details);
12
+ this.code = code;
13
+ this.status = status;
14
+ this.type = type;
15
+ this.warnings = warnings;
16
+ }
17
+ };
18
+
19
+ // src/error/unknown.error.ts
20
+ var UnknownScryfallError = class extends Error {};
21
+
22
+ // src/fetcher/debounce.fetcher.ts
23
+ const defaultNow = () => Date.now();
24
+ async function sleep(milliseconds) {
25
+ await new Promise((resolve) => {
26
+ setTimeout(resolve, milliseconds);
27
+ });
28
+ }
29
+ function createDebounceFetcher(fetcher, { maxRequestsPerSecond, now, sleep: sleepFunction }) {
30
+ const interval = 1e3 / maxRequestsPerSecond;
31
+ const clock = now ?? defaultNow;
32
+ const wait = sleepFunction ?? sleep;
33
+ let lastRequestAt = -Infinity;
34
+ return async function debounceFetcher(...arguments_) {
35
+ for (;;) {
36
+ const currentTime = clock();
37
+ const timeUntilNextRequest = lastRequestAt + interval - currentTime;
38
+ if (timeUntilNextRequest <= 0) {
39
+ lastRequestAt = currentTime;
40
+ break;
41
+ }
42
+ await wait(timeUntilNextRequest);
43
+ }
44
+ return fetcher(...arguments_);
45
+ };
46
+ }
47
+
48
+ // src/fetcher/retry.fetcher.ts
49
+ const defaultCanRetry = (object) => {
50
+ const status = "status" in object ? Number(object.status) : void 0;
51
+ if (status && status >= 500) return true;
52
+ const code = "code" in object && typeof object.code === "string" ? object.code : void 0;
53
+ return code !== "not_found" && code !== "bad_request";
54
+ };
55
+ function createRetryFetcher(fetcher = fetch, { canRetry = defaultCanRetry, maxAttempts = 3 } = {}) {
56
+ let retries = 0;
57
+ return async function retryFetcher(...arguments_) {
58
+ retries++;
59
+ const response = await fetcher(...arguments_);
60
+ if (response.ok) return response;
61
+ const object = await response.json();
62
+ const code = "code" in object && typeof object.code === "string" ? object.code : void 0;
63
+ const status = "status" in object ? Number(object.status) : void 0;
64
+ const details = "details" in object && typeof object.details === "string" ? object.details : void 0;
65
+ const type = "type" in object && typeof object.type === "string" ? object.type : void 0;
66
+ const warnings = "warnings" in object && Array.isArray(object.warnings) ? object.warnings : void 0;
67
+ if (retries >= maxAttempts) {
68
+ if (code && details && status) throw new ScryfallError(code, details, status, type, warnings);
69
+ throw new UnknownScryfallError(`Request failed with status ${response.status.toFixed(0)}`);
70
+ }
71
+ if (canRetry(object)) return retryFetcher(...arguments_);
72
+ if (code && details && status) throw new ScryfallError(code, details, status, type, warnings);
73
+ throw new UnknownScryfallError(`Request failed with status ${response.status.toFixed(0)}`);
74
+ };
75
+ }
76
+
77
+ // src/fetcher/fetcher.ts
78
+ const scryfallEndpoint = "https://api.scryfall.com";
79
+ const defaultRequestsPerSecond = 10;
80
+ const DATE_REGEXP = /^\d{4}-\d{2}-\d{2}?$/;
81
+ const dateParser = (_key, value) => {
82
+ if (typeof value === "string" && DATE_REGEXP.test(value)) return new Date(value);
83
+ return value;
84
+ };
85
+ const globallyLimitedFetch = createDebounceFetcher(fetch, { maxRequestsPerSecond: defaultRequestsPerSecond });
86
+ function createFetcher({ fetch: fetchFunction, maxRequestsPerSecond = defaultRequestsPerSecond, now, sleep } = {}) {
87
+ const globalFetch = fetchFunction ? createDebounceFetcher(fetchFunction, {
88
+ maxRequestsPerSecond: defaultRequestsPerSecond,
89
+ now,
90
+ sleep
91
+ }) : globallyLimitedFetch;
92
+ const retryingFetch = createRetryFetcher(globalFetch);
93
+ const simpleFetcher = maxRequestsPerSecond === defaultRequestsPerSecond ? retryingFetch : createDebounceFetcher(retryingFetch, {
94
+ maxRequestsPerSecond,
95
+ now,
96
+ sleep
97
+ });
98
+ return async function fetcher(apiPath, parameters, body) {
99
+ let path = "";
100
+ if (typeof apiPath === "number" || typeof apiPath === "string") path = apiPath;
101
+ else if (apiPath) path = apiPath.join("/");
102
+ const url = new URL(`${scryfallEndpoint}/${String(path)}`);
103
+ if (parameters) {
104
+ for (const [key, value] of Object.entries(parameters)) if (value !== void 0) url.searchParams.append(key, value.toString());
105
+ }
106
+ try {
107
+ const init = { method: body ? "POST" : "GET" };
108
+ if (body) {
109
+ init.body = JSON.stringify(body);
110
+ init.headers = { "Content-Type": "application/json" };
111
+ }
112
+ const content = await (await simpleFetcher(url, init)).text();
113
+ return JSON.parse(content, dateParser);
114
+ } catch (error) {
115
+ if (error instanceof ScryfallError) {
116
+ if (error.warnings) console.warn(error.warnings);
117
+ if (error.code === "not_found" || error.code === "bad_request") return;
118
+ }
119
+ throw error;
120
+ }
121
+ };
122
+ }
123
+ const fetcher = createFetcher();
124
+
125
+ // src/fetcher/page.result.ts
126
+ var MagicPageResult = class {
127
+ apiPath;
128
+ query;
129
+ fetcher;
130
+ #count = 0;
131
+ #hasMore = true;
132
+ constructor(apiPath, query, fetcher$1 = fetcher) {
133
+ this.apiPath = apiPath;
134
+ this.query = query;
135
+ this.fetcher = fetcher$1;
136
+ }
137
+ get count() {
138
+ return this.#count;
139
+ }
140
+ get hasMore() {
141
+ return this.#hasMore;
142
+ }
143
+ async all() {
144
+ const r = [];
145
+ while (this.#hasMore) {
146
+ const result = await this.next();
147
+ r.push(...result);
148
+ }
149
+ return r;
150
+ }
151
+ async get(limit) {
152
+ const r = [];
153
+ while (this.#hasMore) {
154
+ const result = await this.next();
155
+ r.push(...result);
156
+ if (r.length === limit) return r;
157
+ if (r.length > limit) return r.slice(0, limit);
158
+ }
159
+ return r;
160
+ }
161
+ async next() {
162
+ const results = await this.fetcher(this.apiPath, this.query);
163
+ this.#hasMore = results?.has_more ?? false;
164
+ this.#count = Number.parseInt(results?.total_cards?.toFixed(0) ?? "0", 10);
165
+ if (this.#hasMore) this.setNextPage();
166
+ return results?.data ?? [];
167
+ }
168
+ async page(page) {
169
+ this.query.page = page;
170
+ return this.next();
171
+ }
172
+ setNextPage() {
173
+ this.query.page += 1;
174
+ }
175
+ };
176
+
177
+ // src/api/card/card.api.ts
178
+ const cardsPerSecond = 2;
179
+ const collectionFetcher = createFetcher({ maxRequestsPerSecond: cardsPerSecond });
180
+ const namedFetcher = createFetcher({ maxRequestsPerSecond: cardsPerSecond });
181
+ const randomFetcher = createFetcher({ maxRequestsPerSecond: cardsPerSecond });
182
+ const searchFetcher = createFetcher({ maxRequestsPerSecond: cardsPerSecond });
183
+ var CardApi = class {
184
+ async autoCompleteName(name) {
185
+ return (await fetcher("cards/autocomplete", { q: name }))?.data ?? [];
186
+ }
187
+ async byArenaId(id) {
188
+ return fetcher(["cards/arena", id]);
189
+ }
190
+ async byId(id) {
191
+ return fetcher(["cards", id]);
192
+ }
193
+ async byMtgoId(id) {
194
+ return fetcher(["cards/mtgo", id]);
195
+ }
196
+ async byMultiverseId(id) {
197
+ return fetcher(["cards/multiverse", id]);
198
+ }
199
+ async byName(name, set, isFuzzySearch = false) {
200
+ let isF = isFuzzySearch;
201
+ let s = set;
202
+ if (typeof set === "boolean") {
203
+ isF = set;
204
+ s = void 0;
205
+ }
206
+ return namedFetcher("cards/named", {
207
+ [isF ? "fuzzy" : "exact"]: name,
208
+ set: s
209
+ });
210
+ }
211
+ async bySet(set, collectorNumber, lang) {
212
+ const path = [
213
+ "cards",
214
+ set,
215
+ collectorNumber
216
+ ];
217
+ if (lang) path.push(lang);
218
+ return fetcher(path);
219
+ }
220
+ async byTcgPlayerId(id) {
221
+ return fetcher(["cards/tcgplayer", id]);
222
+ }
223
+ async collection(...identifiers) {
224
+ const cards = [];
225
+ for (let index = 0; index < identifiers.length; index += 75) {
226
+ const collectionSection = { identifiers: identifiers.slice(index, index + 75) };
227
+ const result = await collectionFetcher("cards/collection", void 0, collectionSection);
228
+ cards.push(...result?.data ?? []);
229
+ }
230
+ return cards;
231
+ }
232
+ async random() {
233
+ return randomFetcher("cards/random");
234
+ }
235
+ search(query, options) {
236
+ return new MagicPageResult("cards/search", {
237
+ q: query,
238
+ ...typeof options === "number" ? { page: options } : {
239
+ ...options,
240
+ page: options?.page ?? 1
241
+ }
242
+ }, searchFetcher);
243
+ }
244
+ };
245
+ const cards = new CardApi();
246
+
247
+ // src/api/card-identifier/card-identifier.api.ts
248
+ var CardIdentifierApi = class {
249
+ static byId(id) {
250
+ return { id };
251
+ }
252
+ static byIllustrationId(id) {
253
+ return { illustration_id: id };
254
+ }
255
+ static byMtgoId(id) {
256
+ return { mtgo_id: id };
257
+ }
258
+ static byMultiverseId(id) {
259
+ return { multiverse_id: id };
260
+ }
261
+ static byName(name, set) {
262
+ if (set) return {
263
+ name,
264
+ set
265
+ };
266
+ return { name };
267
+ }
268
+ static byOracleId(id) {
269
+ return { oracle_id: id };
270
+ }
271
+ static bySet(set, collectorNumber) {
272
+ return {
273
+ collector_number: String(collectorNumber),
274
+ set
275
+ };
276
+ }
277
+ };
278
+
279
+ // src/api/catalog/catalog.api.ts
280
+ var CatalogApi = class {
281
+ async artifactTypes() {
282
+ return (await fetcher("catalog/artifact-types"))?.data ?? [];
283
+ }
284
+ async artistNames() {
285
+ return (await fetcher("catalog/artist-names"))?.data ?? [];
286
+ }
287
+ async cardNames() {
288
+ return (await fetcher("catalog/card-names"))?.data ?? [];
289
+ }
290
+ async creatureTypes() {
291
+ return (await fetcher("catalog/creature-types"))?.data ?? [];
292
+ }
293
+ async enchantmentTypes() {
294
+ return (await fetcher("catalog/enchantment-types"))?.data ?? [];
295
+ }
296
+ async landTypes() {
297
+ return (await fetcher("catalog/land-types"))?.data ?? [];
298
+ }
299
+ async loyalties() {
300
+ return (await fetcher("catalog/loyalties"))?.data ?? [];
301
+ }
302
+ async planeswalkerTypes() {
303
+ return (await fetcher("catalog/planeswalker-types"))?.data ?? [];
304
+ }
305
+ async powers() {
306
+ return (await fetcher("catalog/powers"))?.data ?? [];
307
+ }
308
+ async spellTypes() {
309
+ return (await fetcher("catalog/spell-types"))?.data ?? [];
310
+ }
311
+ async toughnesses() {
312
+ return (await fetcher("catalog/toughnesses"))?.data ?? [];
313
+ }
314
+ async watermarks() {
315
+ return (await fetcher("catalog/watermarks"))?.data ?? [];
316
+ }
317
+ async wordBank() {
318
+ return (await fetcher("catalog/word-bank"))?.data ?? [];
319
+ }
320
+ };
321
+ const catalog = new CatalogApi();
322
+
323
+ // src/api/ruling/ruling.api.ts
324
+ var RulingApi = class {
325
+ async byArenaId(id) {
326
+ return (await fetcher([
327
+ "cards/arena",
328
+ id,
329
+ "rulings"
330
+ ]))?.data ?? [];
331
+ }
332
+ async byId(id) {
333
+ return (await fetcher([
334
+ "cards",
335
+ id,
336
+ "rulings"
337
+ ]))?.data ?? [];
338
+ }
339
+ async byMtgoId(id) {
340
+ return (await fetcher([
341
+ "cards/mtgo",
342
+ id,
343
+ "rulings"
344
+ ]))?.data ?? [];
345
+ }
346
+ async byMultiverseId(id) {
347
+ return (await fetcher([
348
+ "cards/multiverse",
349
+ id,
350
+ "rulings"
351
+ ]))?.data ?? [];
352
+ }
353
+ async bySet(set, collectorNumber) {
354
+ return (await fetcher([
355
+ "cards",
356
+ set,
357
+ String(collectorNumber),
358
+ "rulings"
359
+ ]))?.data ?? [];
360
+ }
361
+ };
362
+ const rulings = new RulingApi();
363
+
364
+ // src/api/set/set.api.ts
365
+ var SetApi = class {
366
+ async all() {
367
+ return (await fetcher("sets"))?.data ?? [];
368
+ }
369
+ async byCode(code) {
370
+ return await fetcher(["sets", code]);
371
+ }
372
+ async byId(id) {
373
+ return fetcher(["sets", id]);
374
+ }
375
+ async byTcgPlayerId(id) {
376
+ return fetcher(["sets/tcgplayer", id]);
377
+ }
378
+ };
379
+ const set = new SetApi();
380
+
381
+ // src/api/symbology/symbology.api.ts
382
+ var SymbologyApi = class {
383
+ async all() {
384
+ return (await fetcher("symbology"))?.data ?? [];
385
+ }
386
+ async parseMana(shorthand) {
387
+ if (!shorthand || typeof shorthand !== "string") throw new InvalidScryfallArgumentError("shorthand must be a string");
388
+ return await fetcher("symbology/parse-mana", { cost: shorthand }) ?? {
389
+ cmc: 0,
390
+ colorless: false,
391
+ colors: [],
392
+ cost: "",
393
+ monocolored: false,
394
+ multicolored: false,
395
+ object: "mana_cost"
396
+ };
397
+ }
398
+ };
399
+ const symbology = new SymbologyApi();
400
+
401
+ export { CardIdentifierApi as CardIdentifierBuilder, cards as Cards, catalog as Catalogs, InvalidScryfallArgumentError, MagicPageResult, rulings as Rulings, ScryfallError, set as Sets, symbology as SymbologyApi, UnknownScryfallError };
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "scryfall-api",
3
+ "version": "0.0.0-beta-20261103181737",
4
+ "description": "A Javascript library for https://scryfall.com/docs/api written in Typescript.",
5
+ "keywords": [
6
+ "magic",
7
+ "magic the gathering",
8
+ "magic-the-gathering",
9
+ "gathering",
10
+ "api",
11
+ "mtgsdk",
12
+ "typescript",
13
+ "card",
14
+ "cards",
15
+ "scryfall",
16
+ "scry"
17
+ ],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/MarioMH8/scryfall-api.git"
21
+ },
22
+ "homepage": "https://github.com/MarioMH8/scryfall-api",
23
+ "bugs": {
24
+ "url": "https://github.com/MarioMH8/scryfall-api/issues"
25
+ },
26
+ "license": "MIT",
27
+ "type": "module",
28
+ "files": [
29
+ "dist"
30
+ ],
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/scryfall-api.d.mts",
34
+ "default": "./dist/scryfall-api.mjs"
35
+ }
36
+ },
37
+ "scripts": {
38
+ "build": "tsdown",
39
+ "commitlint": "commitlint --edit",
40
+ "lint": "eslint --cache .",
41
+ "lint:ci": "eslint --cache --cache-strategy content .",
42
+ "lint:fix": "eslint --cache --fix .",
43
+ "lint:package": "bun run build && publint",
44
+ "prepare": "husky",
45
+ "prepublishOnly": "tsdown",
46
+ "test": "bun test --timeout 50000",
47
+ "typecheck": "tsc --noEmit"
48
+ },
49
+ "devDependencies": {
50
+ "@changesets/cli": "3.0.3",
51
+ "@commitlint/cli": "21.2.4",
52
+ "@commitlint/config-conventional": "21.2.4",
53
+ "@hexadrop/eslint-config": "1.3.1",
54
+ "@hexadrop/tsconfig": "0.0.5",
55
+ "@types/bun": "1.4.4",
56
+ "eslint": "10.13.0",
57
+ "husky": "9.1.7",
58
+ "lint-staged": "17.6.0",
59
+ "publint": "0.3.25",
60
+ "tsdown": "0.23.4",
61
+ "typescript": "6.0.3"
62
+ }
63
+ }