@tcgdex/sdk
Version:
Communicate with the Open Source TCGdex API in Javascript/Typescript using the SDK
532 lines (516 loc) • 14.5 kB
JavaScript
// src/tcgdex.ts
import MemoryCache from "@cachex/memory";
import LocalStorageCache from "@cachex/web-storage";
// src/Query.ts
var Query = class _Query {
constructor() {
this.params = [];
this.not = {
equal: (key, value) => {
this.params.push({ key, value: `neq:${value}` });
return this;
},
contains: (key, value) => {
this.params.push({ key, value: `not:${value}` });
return this;
},
includes: (key, value) => this.not.contains(key, value),
like: (key, value) => this.not.contains(key, value),
isNull: (key) => {
this.params.push({ key, value: "notnull:" });
return this;
}
};
}
static create() {
return new _Query();
}
includes(key, value) {
return this.contains(key, value);
}
like(key, value) {
return this.contains(key, value);
}
contains(key, value) {
this.params.push({ key, value });
return this;
}
equal(key, value) {
this.params.push({ key, value: `eq:${value}` });
return this;
}
sort(key, order) {
this.params.push({ key: "sort:field", value: key });
this.params.push({ key: "sort:order", value: order });
return this;
}
greaterOrEqualThan(key, value) {
this.params.push({ key, value: `gte:${value}` });
return this;
}
lesserOrEqualThan(key, value) {
this.params.push({ key, value: `lte:${value}` });
return this;
}
greaterThan(key, value) {
this.params.push({ key, value: `gt:${value}` });
return this;
}
lesserThan(key, value) {
this.params.push({ key, value: `lt:${value}` });
return this;
}
isNull(key) {
this.params.push({ key, value: "null:" });
return this;
}
paginate(page, itemsPerPage) {
this.params.push({ key: "pagination:page", value: page });
this.params.push({ key: "pagination:itemsPerPage", value: itemsPerPage });
return this;
}
};
// src/models/Model.ts
import { objectLoop } from "@dzeio/object-util";
var Model = class {
constructor(sdk) {
this.sdk = sdk;
}
/**
* build a model depending on the data given
* @param model the model to build
* @param data the data to fill it with
*/
static build(model, data) {
if (!data) {
throw new Error("data is necessary.");
}
model.fill(data);
return model;
}
fill(obj) {
objectLoop(obj, (value, key) => {
this[key] = value;
});
}
};
// src/endpoints/Endpoint.ts
var Endpoint = class {
constructor(tcgdex, itemModel, listModel, endpoint) {
this.tcgdex = tcgdex;
this.itemModel = itemModel;
this.listModel = listModel;
this.endpoint = endpoint;
}
async get(id) {
const res = await this.tcgdex.fetch(this.endpoint, id);
if (!res) {
return null;
}
return Model.build(new this.itemModel(this.tcgdex), res);
}
async list(query) {
const res = await this.tcgdex.fetchWithQuery([this.endpoint], query == null ? void 0 : query.params);
return (res != null ? res : []).map((it) => Model.build(new this.listModel(this.tcgdex), it));
}
};
// src/endpoints/SimpleEndpoint.ts
var SimpleEndpoint = class {
constructor(tcgdex, itemModel, endpoint) {
this.tcgdex = tcgdex;
this.itemModel = itemModel;
this.endpoint = endpoint;
}
async get(id) {
const res = await this.tcgdex.fetch(this.endpoint, id);
if (!res) {
return null;
}
return Model.build(new this.itemModel(this.tcgdex), res);
}
async list(query) {
var _a;
return (_a = await this.tcgdex.fetchWithQuery([this.endpoint], query == null ? void 0 : query.params)) != null ? _a : [];
}
};
// src/models/CardResume.ts
var CardResume = class extends Model {
/**
* the the Card Image full URL
*
* @param {Quality} quality the quality you want your image to be in
* @param {Extension} extension extension you want you image to be
* @return the full card URL
*/
getImageURL(quality = "high", extension = "png") {
return `${this.image}/${quality}.${extension}`;
}
/**
* Get the full Card
*
* @return the full card if available
*/
async getCard() {
return await this.sdk.card.get(this.id);
}
};
// src/models/Card.ts
var Card = class extends CardResume {
async getCard() {
return this;
}
async getSet() {
return await this.sdk.set.get(this.set.id);
}
};
// src/models/Serie.ts
import { objectLoop as objectLoop2 } from "@dzeio/object-util";
// src/models/SerieResume.ts
var SerieResume = class extends Model {
/**
* the the Card Image full URL
*
* @param {Quality} quality the quality you want your image to be in
* @param {Extension} extension extension you want you image to be
* @return the full card URL
*/
getImageURL(extension = "png") {
return `${this.logo}.${extension}`;
}
async getSerie() {
return await this.sdk.serie.get(this.id);
}
};
// src/models/SetResume.ts
var SetResume = class extends Model {
async getSet() {
return await this.sdk.set.get(this.id);
}
};
// src/models/Serie.ts
var Serie = class extends SerieResume {
fill(obj) {
objectLoop2(obj, (value, key) => {
switch (key) {
case "sets":
this.sets = value.map((it) => Model.build(new SetResume(this.sdk), it));
break;
default:
this[key] = value;
break;
}
});
}
};
// src/models/Set.ts
import { objectLoop as objectLoop3 } from "@dzeio/object-util";
var Set = class extends Model {
async getSerie() {
return this.sdk.serie.get(this.serie.id);
}
fill(obj) {
objectLoop3(obj, (value, key) => {
switch (key) {
case "cards":
this.cards = value.map((it) => Model.build(new CardResume(this.sdk), it));
break;
default:
this[key] = value;
break;
}
});
}
};
// src/models/StringEndpoint.ts
import { objectLoop as objectLoop4 } from "@dzeio/object-util";
var StringEndpoint = class extends Model {
fill(obj) {
objectLoop4(obj, (value, key) => {
switch (key) {
case "cards":
this.cards = value.map((it) => Model.build(new CardResume(this.sdk), it));
break;
default:
this[key] = value;
break;
}
});
}
};
// src/utils.ts
function detectContext() {
try {
const isBrowser = !!window;
return isBrowser ? "browser" : "server";
} catch {
return "server";
}
}
var ENDPOINTS = [
"cards",
"categories",
"dex-ids",
"energy-types",
"hp",
"illustrators",
"rarities",
"regulation-marks",
"retreats",
"series",
"sets",
"stages",
"suffixes",
"trainer-types",
"types",
"variants",
"random"
];
// src/version.js
var version = "2.7.1";
// src/tcgdex.ts
var _TCGdex = class _TCGdex {
constructor(lang = "en") {
/**
* the previously hidden caching system used by TCGdex to not kill the API
*/
this.cache = detectContext() === "browser" ? new LocalStorageCache("tcgdex-cache") : new MemoryCache();
/**
* the default cache TTL, only subsequent requests will have their ttl changed
*/
this.cacheTTL = 60 * 60;
// random card/set/serie endpoints
this.random = {
card: async () => {
const res = await this.fetch("random", "card");
return Model.build(new Card(this), res);
},
set: async () => {
const res = await this.fetch("random", "set");
return Model.build(new Set(this), res);
},
serie: async () => {
const res = await this.fetch("random", "serie");
return Model.build(new Serie(this), res);
}
};
this.card = new Endpoint(this, Card, CardResume, "cards");
this.set = new Endpoint(this, Set, SetResume, "sets");
this.serie = new Endpoint(this, Serie, SerieResume, "series");
this.type = new SimpleEndpoint(this, StringEndpoint, "types");
this.retreat = new SimpleEndpoint(this, StringEndpoint, "retreats");
this.rarity = new SimpleEndpoint(this, StringEndpoint, "rarities");
this.illustrator = new SimpleEndpoint(this, StringEndpoint, "illustrators");
this.hp = new SimpleEndpoint(this, StringEndpoint, "hp");
this.categorie = new SimpleEndpoint(this, StringEndpoint, "categories");
this.dexID = new SimpleEndpoint(this, StringEndpoint, "dex-ids");
this.energyType = new SimpleEndpoint(this, StringEndpoint, "energy-types");
this.regulationMark = new SimpleEndpoint(this, StringEndpoint, "regulation-marks");
this.stage = new SimpleEndpoint(this, StringEndpoint, "stages");
this.suffixe = new SimpleEndpoint(this, StringEndpoint, "suffixes");
this.trainerType = new SimpleEndpoint(this, StringEndpoint, "trainer-types");
this.variant = new SimpleEndpoint(this, StringEndpoint, "variants");
this.lang = "en";
this.endpointURL = "https://api.tcgdex.net/v2";
this.setLang(lang);
}
/**
* @deprecated use the constructor parameter or {@link TCGdex.setLang} when in an instance
*/
static setDefaultLang(lang) {
_TCGdex.defaultLang = lang;
}
/**
* @deprecated use {@link TCGdex.setLang} when in an instance
*/
static getDefaultLang() {
return _TCGdex.defaultLang;
}
/**
* the endpoint URL
* ex: `https://api.tcgdex.net/v2`
* @param endpoint the url
*/
setEndpoint(endpoint) {
this.endpointURL = endpoint;
}
getEndpoint() {
return this.endpointURL;
}
/**
* set the current cache methodology
* @param cache the cache to use
*/
setCache(cache) {
this.cache = cache;
}
/**
* get the current cache methodology
* @param cache the cache to use
*/
getCache() {
return this.cache;
}
/**
* the endpoint URL
* ex: `https://api.tcgdex.net/v2`
* @param endpoint the url
*/
setCacheTTL(seconds) {
this.cacheTTL = seconds;
}
/**
* get the current useed cache ttl in seconds
* @returns the cache ttl in seconds
*/
getCacheTTL() {
return this.cacheTTL;
}
getLang() {
var _a, _b;
return (_b = (_a = this.lang) != null ? _a : _TCGdex.defaultLang) != null ? _b : "en";
}
setLang(lang) {
this.lang = lang;
}
/**
* 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
*/
async fetchCard(id, set) {
const path = set ? ["sets", set] : ["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
*/
async fetchCards(set) {
if (set) {
const fSet = await this.fetch("sets", set);
return fSet ? fSet.cards : void 0;
}
return this.fetch("cards");
}
/**
* @deprecated use `this.fetch('sets', set)`
*/
async fetchSet(set) {
return this.fetch("sets", set);
}
/**
* @deprecated use `this.fetch('series', serie)`
*/
async fetchSerie(serie) {
return this.fetch("series", serie);
}
/**
* @deprecated use `this.fetch('series')`
*/
async fetchSeries() {
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
*/
async fetchSets(serie) {
if (serie) {
const fSerie = await this.fetch("series", serie);
return fSerie ? fSerie.sets : void 0;
}
return this.fetch("sets");
}
/**
* 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
*/
async fetch(...endpoint) {
if (endpoint.length === 0) {
throw new Error("endpoint to fetch is empty!");
}
const baseEndpoint = endpoint.shift().toLowerCase();
if (!ENDPOINTS.includes(baseEndpoint)) {
throw new Error(`unknown endpoint to fetch! (${baseEndpoint})`);
}
return this.actualFetch(this.getFullURL([baseEndpoint, ...endpoint]));
}
/**
* @param endpoint the endpoint to fetch
* @param query the query
*/
async fetchWithQuery(endpoint, query) {
if (endpoint.length === 0) {
throw new Error("endpoint to fetch is empty!");
}
const baseEndpoint = endpoint[0].toLowerCase();
if (!ENDPOINTS.includes(baseEndpoint)) {
throw new Error(`unknown endpoint to fetch! (${baseEndpoint})`);
}
return this.actualFetch(this.getFullURL(endpoint, query));
}
/**
* format the final URL
*/
getFullURL(path, searchParams) {
const url = new URL(`${this.getEndpoint()}/${this.getLang()}`);
url.pathname = `${url.pathname}/${path.join("/")}`;
for (const param of searchParams != null ? searchParams : []) {
url.searchParams.append(param.key, param.value.toString());
}
return url.toString();
}
async actualFetch(path) {
const cached = this.cache.get(path);
if (cached) {
return cached;
}
const resp = await _TCGdex.fetch(path, {
headers: {
"user-agent": `/javascript-sdk/${version}`
}
});
if (resp.status >= 500) {
try {
const json2 = JSON.stringify(await resp.json());
throw new Error(json2);
} catch {
throw new Error("TCGdex Server responded with an invalid error :(");
}
}
if (resp.status !== 200) {
return void 0;
}
const json = await resp.json();
this.cache.set(path, json, this.cacheTTL);
return json;
}
};
/**
* How the remote data is going to be fetched
*/
_TCGdex.fetch = detectContext() === "browser" ? (...params) => window.fetch(...params) : fetch;
/**
* @deprecated to change the lang use {@link TCGdex.getLang} and {@link TCGdex.setLang}
*/
_TCGdex.defaultLang = "en";
var TCGdex = _TCGdex;
export {
Card as CardModel,
CardResume as CardResumeModel,
Endpoint,
Model,
Query,
Serie as SerieModel,
SerieResume as SerieResumeModel,
Set as SetModel,
SetResume as SetResumeModel,
SimpleEndpoint,
TCGdex as default
};