mirror of
https://github.com/tcgdex/javascript-sdk.git
synced 2025-07-23 14:59:51 +00:00
51
src/Request.ts
Normal file
51
src/Request.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import TCGdex from './tcgdex'
|
||||
|
||||
export default class RequestWrapper {
|
||||
private static cache: Array<Request<any>> = []
|
||||
|
||||
public static getRequest<T>(url: string) {
|
||||
let req = this.cache.find((req) => req.url === url) as Request<T>|undefined
|
||||
if (!req) {
|
||||
req = new Request<T>(url)
|
||||
this.cache.push(req)
|
||||
}
|
||||
return req
|
||||
}
|
||||
}
|
||||
|
||||
export class Request<T = any> {
|
||||
public static ttl = 1000 * 60 * 60 // 1 hour
|
||||
|
||||
private response?: T
|
||||
private fetched?: Date
|
||||
|
||||
public constructor(
|
||||
public url: string // url is public for quick url test
|
||||
) {}
|
||||
|
||||
public async get(): Promise<T | undefined> {
|
||||
const now = new Date()
|
||||
// if reponse was already fetched and TTL was not passed
|
||||
if (
|
||||
this.fetched &&
|
||||
this.response &&
|
||||
now.getTime() - this.fetched.getTime() < Request.ttl
|
||||
) {
|
||||
return this.response
|
||||
}
|
||||
|
||||
// Fetch Response
|
||||
const unfetch = TCGdex.fetch
|
||||
const resp = await unfetch(this.url, {
|
||||
headers: {
|
||||
'user-agent': `@tcgdex/javascript-sdk/${TCGdex.VERSION}`
|
||||
}
|
||||
})
|
||||
if (resp.status !== 200) {
|
||||
return undefined
|
||||
}
|
||||
this.response = await resp.json()
|
||||
this.fetched = now
|
||||
return this.response
|
||||
}
|
||||
}
|
297
src/interfaces.ts
Normal file
297
src/interfaces.ts
Normal file
@ -0,0 +1,297 @@
|
||||
export type SupportedLanguages = 'en' | 'fr'
|
||||
|
||||
export type Languages<T = string> = Partial<Record<SupportedLanguages, T>>
|
||||
|
||||
export interface SerieResume {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface Serie extends SerieResume {
|
||||
sets: SetList
|
||||
}
|
||||
|
||||
interface variants {
|
||||
normal?: boolean
|
||||
reverse?: boolean
|
||||
holo?: boolean
|
||||
firstEdition?: boolean
|
||||
}
|
||||
|
||||
export type SetList = Array<SetResume>
|
||||
export type SerieList = Array<SerieResume>
|
||||
export type CardList = Array<CardResume>
|
||||
|
||||
export interface SetResume {
|
||||
id: string
|
||||
name: string
|
||||
logo?: string
|
||||
symbol?: string
|
||||
cardCount: {
|
||||
/**
|
||||
* total of number of cards
|
||||
*/
|
||||
total: number
|
||||
/**
|
||||
* number of cards officialy (on the bottom of each cards)
|
||||
*/
|
||||
official: number
|
||||
}
|
||||
}
|
||||
|
||||
export interface Set extends SetResume {
|
||||
serie: SerieResume
|
||||
tcgOnline?: string
|
||||
variants?: variants
|
||||
|
||||
releaseDate: string
|
||||
|
||||
/**
|
||||
* Designate if the set is usable in tournaments
|
||||
*
|
||||
* Note: this is specific to the set and if a
|
||||
* card is banned from the set it will still be true
|
||||
*/
|
||||
legal: {
|
||||
/**
|
||||
* Ability to play in standard tournaments
|
||||
*/
|
||||
standard: boolean
|
||||
|
||||
/**
|
||||
* Ability to play in expanded tournaments
|
||||
*/
|
||||
expanded: boolean
|
||||
}
|
||||
|
||||
cardCount: {
|
||||
/**
|
||||
* total of number of cards
|
||||
*/
|
||||
total: number
|
||||
/**
|
||||
* number of cards officialy (on the bottom of each cards)
|
||||
*/
|
||||
official: number
|
||||
/**
|
||||
* number of cards having a normal version
|
||||
*/
|
||||
normal: number
|
||||
/**
|
||||
* number of cards having an reverse version
|
||||
*/
|
||||
reverse: number
|
||||
/**
|
||||
* number of cards having an holo version
|
||||
*/
|
||||
holo: number
|
||||
/**
|
||||
* Number of possible cards
|
||||
*/
|
||||
firstEd?: number
|
||||
}
|
||||
|
||||
cards: CardList
|
||||
}
|
||||
|
||||
export interface CardResume {
|
||||
id: string
|
||||
localId: string
|
||||
|
||||
/**
|
||||
* Card Name (Including the suffix if next to card name)
|
||||
*/
|
||||
name: string
|
||||
image?: string
|
||||
}
|
||||
|
||||
export interface Card<SetType extends SetResume = SetResume> extends CardResume {
|
||||
|
||||
/**
|
||||
* Card illustrator
|
||||
*/
|
||||
illustrator?: string
|
||||
|
||||
/**
|
||||
* Card Rarity
|
||||
*
|
||||
* - None https://www.tcgdex.net/database/sm/smp/SM01
|
||||
* - Common https://www.tcgdex.net/database/xy/xy9/1
|
||||
* - Uncommon https://www.tcgdex.net/database/xy/xy9/2
|
||||
* - Rare https://www.tcgdex.net/database/xy/xy9/3
|
||||
* - Ultra Rare
|
||||
* - Secret Rare
|
||||
*/
|
||||
rarity: string
|
||||
|
||||
/**
|
||||
* Card Category
|
||||
*
|
||||
* - Pokemon
|
||||
* - Trainer
|
||||
* - Energy
|
||||
*/
|
||||
category: string
|
||||
|
||||
/**
|
||||
* Card Variants (Override Set Variants)
|
||||
*/
|
||||
variants?: variants
|
||||
|
||||
/**
|
||||
* Card Set
|
||||
*/
|
||||
set: SetType
|
||||
|
||||
/**
|
||||
* Pokemon only elements
|
||||
*/
|
||||
|
||||
/**
|
||||
* Pokemon Pokedex ID
|
||||
*/
|
||||
dexId?: Array<number>
|
||||
|
||||
/**
|
||||
* Pokemon HP
|
||||
*/
|
||||
hp?: number
|
||||
|
||||
/**
|
||||
* Pokemon Types
|
||||
*/
|
||||
types?: Array<string> // ex for multiple https://www.tcgdex.net/database/ex/ex13/17
|
||||
|
||||
/**
|
||||
* Pokemon Sub Evolution
|
||||
*/
|
||||
evolveFrom?: string
|
||||
|
||||
/**
|
||||
* Pokemon Weight
|
||||
*/
|
||||
weight?: string
|
||||
|
||||
/**
|
||||
* Pokemon Description
|
||||
*/
|
||||
description?: string
|
||||
|
||||
/**
|
||||
* Level of the Pokemon
|
||||
*
|
||||
* NOTE: can be equal to 'X' when the pokemon is a LEVEL-UP one
|
||||
*/
|
||||
level?: number | string
|
||||
|
||||
/**
|
||||
* Pokemon Stage
|
||||
*
|
||||
* - Basic https://www.tcgdex.net/database/xy/xy9/1
|
||||
* - BREAK https://www.tcgdex.net/database/xy/xy9/18
|
||||
* - LEVEL-UP https://www.tcgdex.net/database/dp/dp1/121
|
||||
* - MEGA https://www.tcgdex.net/database/xy/xy1/2
|
||||
* - RESTORED https://www.tcgdex.net/database/bw/bw5/53
|
||||
* - Stage1 https://www.tcgdex.net/database/xy/xy9/2
|
||||
* - Stage2 https://www.tcgdex.net/database/xy/xy9/3
|
||||
* - VMAX https://www.tcgdex.net/database/swsh/swsh1/50
|
||||
*/
|
||||
stage?: string
|
||||
|
||||
/**
|
||||
* Card Suffix
|
||||
*
|
||||
* - EX https://www.tcgdex.net/database/ex/ex2/94
|
||||
* - GX https://www.tcgdex.net/database/sm/sm12/4
|
||||
* - V https://www.tcgdex.net/database/swsh/swsh1/1
|
||||
* - Legend https://www.tcgdex.net/database/hgss/hgss1/114
|
||||
* - Prime https://www.tcgdex.net/database/hgss/hgss2/85
|
||||
* - SP https://www.tcgdex.net/database/pl/pl1/7
|
||||
* - TAG TEAM-GX https://www.tcgdex.net/database/sm/sm12/226
|
||||
*/
|
||||
suffix?: string
|
||||
|
||||
/**
|
||||
* Pokemon Held Item
|
||||
*
|
||||
* ex https://www.tcgdex.net/database/dp/dp2/75
|
||||
*/
|
||||
item?: {
|
||||
name: string
|
||||
effect: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Pokemon Abilities
|
||||
*
|
||||
* multi abilities ex https://www.tcgdex.net/database/ex/ex15/10
|
||||
*/
|
||||
abilities?: Array<{
|
||||
type: string
|
||||
name: string
|
||||
effect: string
|
||||
}>
|
||||
|
||||
/**
|
||||
* Pokemon Attacks
|
||||
*/
|
||||
attacks?: Array<{
|
||||
cost?: Array<string>
|
||||
name: string
|
||||
effect?: string
|
||||
damage?: string | number
|
||||
}>
|
||||
|
||||
/**
|
||||
* Pokemon Weaknesses
|
||||
*/
|
||||
weaknesses?: Array<{
|
||||
type: string
|
||||
value?: string
|
||||
}>
|
||||
|
||||
resistances?: Array<{
|
||||
type: string
|
||||
value?: string
|
||||
}>
|
||||
|
||||
retreat?: number
|
||||
|
||||
//Trainer/Energy
|
||||
effect?: string
|
||||
|
||||
// Trainer Only
|
||||
trainerType?: string
|
||||
|
||||
// Energy Only
|
||||
energyType?: string
|
||||
|
||||
/**
|
||||
* Define the rotation mark on cards >= Sword & Shield
|
||||
*/
|
||||
regulationMark?: string
|
||||
|
||||
/**
|
||||
* Card ability to be played in official tournaments
|
||||
*
|
||||
* Note: all cards are avaialable to play in unlimited tournaments
|
||||
*/
|
||||
legal: {
|
||||
/**
|
||||
* Ability to play in standard tournaments
|
||||
*/
|
||||
standard: boolean
|
||||
|
||||
/**
|
||||
* Ability to play in expanded tournaments
|
||||
*/
|
||||
expanded: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export type StringEndpointList = Array<string>
|
||||
|
||||
export interface StringEndpoint {
|
||||
name: string
|
||||
cards: Array<CardResume>
|
||||
}
|
7
src/tcgdex.browser.ts
Normal file
7
src/tcgdex.browser.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import TCGdex from './tcgdex'
|
||||
import unfetch from 'unfetch'
|
||||
|
||||
TCGdex.fetch = unfetch as any
|
||||
|
||||
export default TCGdex
|
||||
export * from './tcgdex'
|
7
src/tcgdex.node.ts
Normal file
7
src/tcgdex.node.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import TCGdex from './tcgdex'
|
||||
import fetch from 'node-fetch'
|
||||
|
||||
TCGdex.fetch = fetch as any
|
||||
|
||||
export default TCGdex
|
||||
export * from './tcgdex'
|
177
src/tcgdex.ts
Normal file
177
src/tcgdex.ts
Normal file
@ -0,0 +1,177 @@
|
||||
import RequestWrapper from './Request'
|
||||
import { Serie, Set, Card, CardResume, SerieList, SetList, SupportedLanguages, StringEndpoint } from './interfaces'
|
||||
type Endpoint = 'cards' | 'categories' | 'hp' | 'illustrators' | 'rarities' | 'retreats' | 'series' | 'sets' | 'types'
|
||||
|
||||
const ENDPOINTS: Array<Endpoint> = ['cards', 'categories', 'hp', 'illustrators', 'rarities', 'retreats', 'series', 'sets', 'types']
|
||||
const BASE_URL = 'https://api.tcgdex.net/v2'
|
||||
export default class TCGdex {
|
||||
|
||||
|
||||
public static fetch: typeof fetch
|
||||
|
||||
public static readonly VERSION = "2.2.0"
|
||||
|
||||
/**
|
||||
* @deprecated to change the lang use `this.lang`
|
||||
*/
|
||||
public static defaultLang: SupportedLanguages = "en"
|
||||
|
||||
public constructor(public lang?: SupportedLanguages) {}
|
||||
|
||||
public getLang() {
|
||||
return this.lang ?? TCGdex.defaultLang ?? 'en'
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to easily fetch a card using both it's global id and it's local ID
|
||||
* @param id the card global/local ID
|
||||
* @param set the card set name/ID (optionnal)
|
||||
* @returns the card object
|
||||
*/
|
||||
public async fetchCard(id: string | number, set?: string): Promise<Card | undefined> {
|
||||
const path = set ? ['sets', set] : ['cards']
|
||||
// @ts-expect-error the base endpoint is 'sets' or 'cards'
|
||||
return this.fetch(...path, id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to easily fetch cards using an optionnal set name/ID
|
||||
* @param set the card set name/ID (optionnal)
|
||||
* @returns a card list
|
||||
*/
|
||||
public async fetchCards(set?: string): Promise<Array<CardResume> | undefined> {
|
||||
if (set) {
|
||||
const fSet = await this.fetch('sets', set)
|
||||
return fSet ? fSet.cards : undefined
|
||||
}
|
||||
return this.fetch('cards')
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `this.fetch('sets', set)`
|
||||
*/
|
||||
public async fetchSet(set: string) {
|
||||
return this.fetch('sets', set)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `this.fetch('series', serie)`
|
||||
*/
|
||||
public async fetchSerie(serie: string): Promise<Serie | undefined> {
|
||||
return this.fetch('series', serie)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `this.fetch('series')`
|
||||
*/
|
||||
public async fetchSeries(): Promise<SerieList | undefined> {
|
||||
return this.fetch('series')
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to easily fetch sets using an optionnal serie name/ID
|
||||
* @param serie the card set name/ID (optionnal)
|
||||
* @returns a card list
|
||||
*/
|
||||
public async fetchSets(serie?: string): Promise<SetList | undefined> {
|
||||
if (serie) {
|
||||
const fSerie = await this.fetch('series', serie)
|
||||
return fSerie ? fSerie.sets : undefined
|
||||
}
|
||||
return this.fetch('sets')
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a card using its global id
|
||||
* @param endpoint_0 'cards'
|
||||
* @param endpoint_1 {string} the card global ID
|
||||
*/
|
||||
public async fetch(...type: ['cards', string]): Promise<Card | undefined>
|
||||
/**
|
||||
* Fetch every cards in the database
|
||||
* @param endpoint_0 'cards'
|
||||
*/
|
||||
public async fetch(type: 'cards'): Promise<Array<CardResume> | undefined>
|
||||
/**
|
||||
* Fetch a card using its local id and its set
|
||||
* @param endpoint_0 'sets'
|
||||
* @param endpoint_1 {string} the set name or ID
|
||||
* @param endpoint_2 {string} the card local ID
|
||||
*/
|
||||
public async fetch(...endpoint: ['sets', string, string]): Promise<Card | undefined>
|
||||
/**
|
||||
* Fetch a set
|
||||
* @param endpoint_0 'sets'
|
||||
* @param endpoint_1 {string} the set name or ID
|
||||
*/
|
||||
public async fetch(...endpoint: ['sets', string]): Promise<Set | undefined>
|
||||
/**
|
||||
* Fetch every sets
|
||||
* @param endpoint_0 'sets'
|
||||
*/
|
||||
public async fetch(endpoint: 'sets'): Promise<SetList | undefined>
|
||||
/**
|
||||
* Fetch a serie
|
||||
* @param endpoint_0 'series'
|
||||
* @param endpoint_1 {string} the serie name or ID
|
||||
*/
|
||||
public async fetch(...endpoint: ['series', string]): Promise<Serie | undefined>
|
||||
/**
|
||||
* Fetch every series
|
||||
* @param endpoint_0 'series'
|
||||
*/
|
||||
public async fetch(endpoint: 'series'): Promise<SerieList | undefined>
|
||||
/**
|
||||
* Fetch cards depending on a specific filter
|
||||
* @param endpoint_0 {'categories' | 'hp' | 'illustrators' | 'rarities' | 'retreats' | 'types'}
|
||||
* Possible value 'categories' | 'hp' | 'illustrators' | 'rarities' | 'retreats' | 'types'
|
||||
* @param endpoint_1 {string} the value set while fetching the index
|
||||
*/
|
||||
public async fetch(...endpoint: ['categories' | 'hp' | 'illustrators' | 'rarities' | 'retreats' | 'types', string]): Promise<StringEndpoint | undefined>
|
||||
/**
|
||||
* Fetch cards depending on a specific filter
|
||||
* @param endpoint_0 {'hp' | 'retreats' | 'categories' | 'illustrators' | 'rarities' | 'types'}
|
||||
* Possible value 'hp' | 'retreats' | 'categories' | 'illustrators' | 'rarities' | 'types'
|
||||
* @param endpoint_1 {string} Fetch the possible values to use depending on the endpoint
|
||||
*/
|
||||
public async fetch(endpoint: 'hp' | 'retreats' | 'categories' | 'illustrators' | 'rarities' | 'types'): Promise<Array<string> | undefined>
|
||||
/**
|
||||
* Fetch The differents endpoints depending on the first argument
|
||||
* @param endpoint_0 {'hp' | 'retreats' | 'categories' | 'illustrators' | 'rarities' | 'types'}
|
||||
* Possible value 'cards' | 'categories' | 'hp' | 'illustrators' | 'rarities' | 'retreats' | 'series' | 'sets' | 'types'
|
||||
* @param endpoint_1 {string} (Optionnal) some details to go from the index file to the item file (mostly the ID/name)
|
||||
* @param endpoint_2 {string} (Optionnal) only for sets the card local ID to fetch the card through the set
|
||||
*/
|
||||
public async fetch(...endpoint: Array<Endpoint | string>): Promise<any | undefined> {
|
||||
if (endpoint.length === 0) {
|
||||
throw new Error(`endpoint to fetch is empty!`)
|
||||
}
|
||||
// @ts-expect-error with the precedent check, we KNOW that type is not empty
|
||||
const baseEndpoint = endpoint.shift().toLowerCase() as Endpoint
|
||||
if (!ENDPOINTS.includes(baseEndpoint)) {
|
||||
throw new Error(`unknown endpoint to fetch! (${baseEndpoint})`)
|
||||
}
|
||||
return this.makeRequest(baseEndpoint, ...endpoint)
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to make the request and normalize the whole path
|
||||
*/
|
||||
private makeRequest<T = any>(...url: Array<string | number>) {
|
||||
// Normalize path
|
||||
const path = url.map((v) => encodeURI(
|
||||
v
|
||||
// Transform numbers to string
|
||||
.toString()
|
||||
// replace this special character with an escaped one
|
||||
.replace('?', '%3F')
|
||||
// normalize the string
|
||||
.normalize('NFC')
|
||||
// remove some special chars by nothing
|
||||
.replace(/["'\u0300-\u036f]/g, "")
|
||||
)).join('/')
|
||||
return RequestWrapper.getRequest<T>(`${BASE_URL}/${this.getLang()}/${path}`).get()
|
||||
}
|
||||
}
|
||||
|
||||
export * from './interfaces'
|
Reference in New Issue
Block a user