Compare commits

...

15 Commits

Author SHA1 Message Date
dependabot[bot]
c866b4022f
build: bump @babel/core from 7.20.12 to 7.26.7 (#293)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.20.12 to 7.26.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.7/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-05 17:17:04 +01:00
dependabot[bot]
978a676a79
build: bump vite from 5.4.11 to 5.4.14 (#292)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-27 15:33:48 +01:00
dependabot[bot]
1f801f4a94
build: bump @typescript-eslint/eslint-plugin from 5.48.1 to 5.62.0 (#291)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-27 15:33:03 +01:00
4e4bcf9d26
2.6.0 2025-01-14 16:33:47 +01:00
0b14e8ddec
fix: export models (#290) 2025-01-14 16:27:21 +01:00
dependabot[bot]
fc4a31ef39
build: bump typescript from 5.1.5 to 5.7.3 (#289)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 10:28:26 +01:00
26acb1eb61
fix: test failing after 30s
Signed-off-by: Avior <git@avior.me>
2024-12-10 11:35:59 +01:00
c03183bd6f
fix: test failing after 30s
Signed-off-by: Avior <git@avior.me>
2024-12-10 11:32:19 +01:00
07403cb3ae
fix: update cachex deps
Signed-off-by: Avior <git@avior.me>
2024-12-02 16:39:16 +01:00
dependabot[bot]
f5dd4cb88c
build: bump json5 from 2.2.1 to 2.2.3 (#257)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-28 00:41:24 +01:00
dependabot[bot]
9b9ff2f028
build: bump @dzeio/config from 1.1.9 to 1.1.12 (#247)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-28 00:41:12 +01:00
dependabot[bot]
ce64a95f4e
build: bump eslint from 8.31.0 to 8.35.0 (#271)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-28 00:40:54 +01:00
dependabot[bot]
460f101026
build: bump @typescript-eslint/parser from 5.48.1 to 5.54.1 (#273)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-28 00:40:45 +01:00
b3ba7820a3
chore: remove unused tests
Signed-off-by: Avior <git@avior.me>
2024-11-11 22:35:49 +01:00
1f3aae5401
feat: Add CacheX for cache management (#281) 2024-11-11 16:50:45 +01:00
11 changed files with 3555 additions and 1197 deletions

View File

@ -1,18 +1,19 @@
/// <reference types="jest" />
import { expect, test, vi } from 'vitest'
import TCGdex, { Query } from '../src/tcgdex'
const { default: TCGdex, Query } = require("../src/tcgdex")
import fetch from 'node-fetch'
// change timeout of execution
vi.setConfig({ testTimeout: 120000 })
const fakeFetch = (response, status = 200) => jest.fn(() =>
const fakeFetch = (response: any, status = 200) => vi.fn(() =>
Promise.resolve({
status: status,
json: () => Promise.resolve(response),
json: () => Promise.resolve(response)
})
);
)
test('Basic test', async () => {
const tcgdex = new TCGdex('en')
TCGdex.fetch = fakeFetch({ ok: true })
TCGdex.fetch = fakeFetch({ ok: true }) as any
const res = await tcgdex.fetch('cards', 'basic-test')
expect(res).toEqual({ ok: true })
expect(TCGdex.fetch).toHaveBeenCalledTimes(1)
@ -20,7 +21,7 @@ test('Basic test', async () => {
test('endpoint errors', async () => {
const tcgdex = new TCGdex('en')
TCGdex.fetch = fakeFetch({ ok: 'a' })
TCGdex.fetch = fakeFetch({ ok: 'a' }) as any
await expect(tcgdex.fetch('non existing endpoint')).rejects.toThrow()
await expect(tcgdex.fetch()).rejects.toThrow()
})
@ -67,7 +68,7 @@ test(`test get set from card`, async () => {
TCGdex.fetch = fetch
expect(
await (await tcgdex.card.get('swsh1-136')).getSet()
await (await tcgdex.card.get('swsh1-136'))!.getSet()
).toBeTruthy()
})
@ -76,7 +77,7 @@ test(`test get serie from set`, async () => {
TCGdex.fetch = fetch
expect(
await (await tcgdex.set.get('swsh1')).getSerie()
await (await tcgdex.set.get('swsh1'))!.getSerie()
).toBeTruthy()
})

View File

@ -1,54 +0,0 @@
/// <reference types="jest" />
const { default: MemoryCache } = require("../src/Psr/SimpleCache/MemoryCache")
const TCGdex = require("../src/tcgdex").default
test('that cache store and get one element', async () => {
const cache = new MemoryCache()
cache.set('a', 'b')
expect(cache.get('a')).toBe('b')
})
test('that cache store and get multiple elements', async () => {
const cache = new MemoryCache()
cache.setMultiple({
'a': 'b',
'c': 'd'
})
expect(cache.getMultiple(['a', 'c'])).toStrictEqual({
a: 'b',
c: 'd'
})
})
test('cache expiration', async () => {
const cache = new MemoryCache()
cache.set('a', 'b', 1)
// wait 2 secs
await new Promise((res) => setTimeout(res, 2000))
expect(cache.get('a')).toBeUndefined()
})
test('cache deletion', async () => {
const cache = new MemoryCache()
cache.set('a', 'b')
expect(cache.get('a')).toBe('b')
cache.delete('a')
expect(cache.get('a')).toBeUndefined()
})
test('cache cleared', async () => {
const cache = new MemoryCache()
cache.set('a', 'b')
expect(cache.get('a')).toBe('b')
cache.clear()
expect(cache.get('a')).toBeUndefined()
})
test('cache exists', async () => {
const cache = new MemoryCache()
expect(cache.has('a')).toBe(false)
cache.set('a', 'b')
expect(cache.has('a')).toBe(true)
})

View File

@ -1,43 +1,44 @@
const TCGdex = require("../src/tcgdex").default
const fetch = require('node-fetch')
import { expect, test, vi } from 'vitest'
import TCGdex from '../src/tcgdex'
const fakeFetch = (response, status = 200) => jest.fn(() =>
// change timeout of execution
vi.setConfig({ testTimeout: 120000 })
const fakeFetch = (response, status = 200) => vi.fn(() =>
Promise.resolve({
status: status,
json: () => Promise.resolve(response),
})
);
)
test('Basic test', async () => {
const tcgdex = new TCGdex('en')
TCGdex.fetch = fakeFetch({ok: true})
TCGdex.fetch = fakeFetch({ ok: true }) as any
const res = await tcgdex.fetch('cards', 'basic-test')
expect(res).toEqual({ok: true})
expect(res).toEqual({ ok: true })
expect(TCGdex.fetch).toHaveBeenCalledTimes(1)
})
test('Cache test', async () => {
const tcgdex = new TCGdex('en')
TCGdex.fetch = fakeFetch({ok: 'a'})
TCGdex.fetch = fakeFetch({ ok: 'a' }) as any
const res1 = await tcgdex.fetch('cards', 'cache-test')
expect(res1).toEqual({ok: 'a'})
TCGdex.fetch = fakeFetch({ok: 'b'})
expect(res1).toEqual({ ok: 'a' })
TCGdex.fetch = fakeFetch({ ok: 'b' }) as any
const res2 = await tcgdex.fetch('cards', 'cache-test')
expect(res2).toEqual({ok: 'a'})
expect(res2).toEqual({ ok: 'a' })
})
test('endpoint errors', async () => {
const tcgdex = new TCGdex('en')
TCGdex.fetch = fakeFetch({ok: 'a'})
TCGdex.fetch = fakeFetch({ ok: 'a' }) as any
await expect(tcgdex.fetch('non existing endpoint')).rejects.toThrow()
await expect(tcgdex.fetch()).rejects.toThrow()
})
test('404 test', async () => {
const tcgdex = new TCGdex('en')
TCGdex.fetch = fakeFetch(undefined, 404)
TCGdex.fetch = fakeFetch(undefined, 404) as any
expect(
await tcgdex.fetch('cards', '404-test')
).not.toBeDefined()
@ -47,15 +48,15 @@ test('test real endpoints', async () => {
const tcgdex = new TCGdex('en')
TCGdex.fetch = fetch
const endpoints = [
{endpoint: 'fetchCard', params: ['swsh1-1']},
{endpoint: 'fetchCard', params: ['1', 'Sword & Shield']},
{endpoint: 'fetchCards', params: ['swsh1']},
{endpoint: 'fetchCards', params: []},
{endpoint: 'fetchSet', params: ['swsh1']},
{endpoint: 'fetchSets', params: ['swsh']},
{endpoint: 'fetchSets', params: []},
{endpoint: 'fetchSeries', params: []},
{endpoint: 'fetchSerie', params: ['swsh']},
{ endpoint: 'fetchCard', params: ['swsh1-1'] },
{ endpoint: 'fetchCard', params: ['1', 'Sword & Shield'] },
{ endpoint: 'fetchCards', params: ['swsh1'] },
{ endpoint: 'fetchCards', params: [] },
{ endpoint: 'fetchSet', params: ['swsh1'] },
{ endpoint: 'fetchSets', params: ['swsh'] },
{ endpoint: 'fetchSets', params: [] },
{ endpoint: 'fetchSeries', params: [] },
{ endpoint: 'fetchSerie', params: ['swsh'] },
]
for await (const item of endpoints) {

4305
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "@tcgdex/sdk",
"version": "2.6.0-beta.3",
"version": "2.6.0",
"main": "./dist/tcgdex.node.js",
"module": "./dist/tcgdex.node.mjs",
"types": "./dist/tcgdex.node.d.ts",
@ -44,15 +44,19 @@
"@types/node-fetch": "^2",
"@typescript-eslint/eslint-plugin": "^5",
"@typescript-eslint/parser": "^5",
"@vitest/coverage-v8": "^2.1.8",
"eslint": "^8",
"jest": "^29",
"tsup": "^7",
"typescript": "^5"
"typescript": "^5",
"vitest": "^2"
},
"engines": {
"node": ">=12"
},
"dependencies": {
"@cachex/memory": "^1",
"@cachex/web-storage": "^1",
"@dzeio/object-util": "^1",
"isomorphic-unfetch": "^3"
},
@ -61,7 +65,7 @@
"build": "rm -rf dist && tsup ./src/tcgdex.node.ts --format cjs,esm --dts --clean && tsup ./src/tcgdex.browser.ts --format iife --global-name TCGdex --sourcemap",
"prepublishOnly": "npm run build",
"lint": "eslint",
"test": "jest --coverage"
"test": "vitest run --coverage"
},
"files": [
"dist"

View File

@ -1,38 +0,0 @@
import { objectLoop } from '@dzeio/object-util'
import type CacheInterface from './CacheInterface'
export default abstract class CacheAsbract implements CacheInterface {
public getMultiple<T>(keys: Array<string>, defaultValues?: Array<T> | undefined): Record<string, T> {
const res: Record<string, T> = {}
for (let idx = 0; idx < keys.length; idx++) {
const key = keys[idx] as string
const value = this.get(key, defaultValues?.[idx]) as T | undefined
if (typeof value === 'undefined') {
continue
}
res[key] = value
}
return res
}
public setMultiple<T>(values: Record<string, T>, ttl?: number | undefined): boolean {
objectLoop(values, (v, k) => {
this.set(k, v, ttl)
})
return true
}
public deleteMultiple(keys: Array<string>): boolean {
for (const key of keys) {
this.delete(key)
}
return true
}
public abstract get<T>(key: string, defaultValue?: T): T | undefined
public abstract set<T>(key: string, value: T, ttl?: number): boolean
public abstract delete(key: string): boolean
public abstract clear(): boolean
public abstract has(key: string): boolean
}

View File

@ -1,109 +0,0 @@
export default interface CacheInterface {
/**
* Fetches a value from the cache.
*
* @param key The unique key of this item in the cache.
* @param defaultValue Default value to return if the key does not exist.
*
* @return T The value of the item from the cache, or $default in case of cache miss.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
get<T>(key: string, defaultValue?: T): T | undefined
/**
* Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time.
*
* @param key The key of the item to store.
* @param value The value of the item to store. Must be serializable.
* @param {null|number} ttl The TTL value of this item. If no value is sent and
* the driver supports TTL then the library may set a default value
* for it or let the driver take care of that.
*
* @return bool True on success and false on failure.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
set<T>(key: string, value: T, ttl?: number): boolean
/**
* Delete an item from the cache by its unique key.
*
* @param key The unique cache key of the item to delete.
*
* @return True if the item was successfully removed. False if there was an error.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
delete(key: string): boolean
/**
* Wipes clean the entire cache's keys.
*
* @return boolean True on success and false on failure.
*/
clear(): boolean
/**
* Obtains multiple cache items by their unique keys.
*
* @param keys A list of keys that can obtained in a single operation.
* @param defaultValues $default Default value to return for keys that do not exist.
*
* @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if $keys is neither an array nor a Traversable,
* or if any of the $keys are not a legal value.
*/
getMultiple<T>(keys: Array<string>, defaultValues?: Array<T>): Record<string, T>
/**
* Persists a set of key => value pairs in the cache, with an optional TTL.
*
* @param values A list of key => value pairs for a multiple-set operation.
* @param ttl Optional. The TTL value of this item. If no value is sent and
* the driver supports TTL then the library may set a default value
* for it or let the driver take care of that.
*
* @return bool True on success and false on failure.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if $values is neither an array nor a Traversable,
* or if any of the $values are not a legal value.
*/
setMultiple<T>(values: Record<string, T>, ttl?: number): boolean
/**
* Deletes multiple cache items in a single operation.
*
* @param keys A list of string-based keys to be deleted.
*
* @return bool True if the items were successfully removed. False if there was an error.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if $keys is neither an array nor a Traversable,
* or if any of the $keys are not a legal value.
*/
deleteMultiple(keys: Array<string>): boolean
/**
* Determines whether an item is present in the cache.
*
* NOTE: It is recommended that has() is only to be used for cache warming type purposes
* and not to be used within your live applications operations for get/set, as this method
* is subject to a race condition where your has() will return true and immediately after,
* another script can remove it, making the state of your app out of date.
*
* @param key The cache item key.
*
* @return bool
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
has(key: string): boolean
}

View File

@ -1,91 +0,0 @@
import CacheAsbract from './CacheAbstract'
interface CacheItem<T> {
data: T
expire?: number | undefined
}
/**
* A cache implementation that uses browser storage.
*
* This class extends `CacheAsbract` and provides a concrete implementation
* of the caching interface. It stores cached items in browser storage,
* which is suitable for storing small amounts of data.
*/
export default class BrowserStorageCache extends CacheAsbract {
private storage: Storage
public constructor(private readonly prefix?: string, session = false) {
super()
if (session) {
this.storage = window.sessionStorage
} else {
this.storage = window.localStorage
}
}
public get<T>(key: string, defaultValue?: T | undefined): T | undefined {
const raw = this.storage.getItem(this.getFinalKey(key))
if (!raw) {
return defaultValue ?? undefined
}
const item: CacheItem<T> = JSON.parse(raw)
if (item.expire && item.expire < new Date().getTime()) {
this.delete(key)
return defaultValue ?? undefined
}
return item.data
}
public set<T>(key: string, value: T, ttl?: number | undefined): boolean {
let expire = undefined
if (ttl) {
expire = (new Date()).getTime() + (ttl * 1000)
}
const data: CacheItem<unknown> = {
data: value,
expire: expire
}
this.storage.setItem(this.getFinalKey(key), JSON.stringify(data))
return true
}
public delete(key: string): boolean {
this.storage.removeItem(this.getFinalKey(key))
return true
}
public clear(): boolean {
const keys = this.keys()
return this.deleteMultiple(keys)
}
public has(key: string): boolean {
return !!this.storage.getItem(this.getFinalKey(key))
}
private keys(): Array<string> {
const list: Array<string> = []
for (let idx = 0; idx < this.storage.length; idx++) {
const key = this.storage.key(idx)
if (!key || this.prefix && !key?.startsWith(`${this.prefix}/`)) {
continue
}
list.push(key)
}
return list
}
private getFinalKey(key: string): string {
if (!this.prefix) {
return key
}
return `${this.prefix}/${key}`
}
}

View File

@ -1,58 +0,0 @@
import CacheAsbract from './CacheAbstract'
interface CacheItem<T> {
data: T
expire?: number | undefined
}
/**
* Memory cache implementation that stores cached items in memory.
* This class extends the abstract `CacheAbstract` and provides a basic in-memory caching mechanism.
*
* @class MemoryCache
*/
export default class MemoryCache extends CacheAsbract {
private cache: Map<string, CacheItem<unknown>> = new Map()
public get<T>(key: string, defaultValue?: T | undefined): T | undefined {
const item = this.cache.get(key)
if (!item) {
return defaultValue ?? undefined
}
if (item.expire && item.expire < new Date().getTime()) {
this.delete(key)
return defaultValue ?? undefined
}
return item.data as T | undefined
}
public set<T>(key: string, value: T, ttl?: number | undefined): boolean {
let expire: number | undefined
if (ttl) {
expire = new Date().getTime() + ttl * 1000
}
this.cache.set(key, {
data: value,
expire: expire
})
return true
}
public delete(key: string): boolean {
this.cache.delete(key)
return true
}
public clear(): boolean {
this.cache.clear()
return true
}
public has(key: string): boolean {
return this.cache.has(key)
}
}

View File

@ -1,6 +1,6 @@
import type CacheInterface from './Psr/SimpleCache/CacheInterface'
import LocalStorageCache from './Psr/SimpleCache/LocalStorageCache'
import MemoryCache from './Psr/SimpleCache/MemoryCache'
import type CacheInterface from '@cachex/core'
import MemoryCache from '@cachex/memory'
import LocalStorageCache from '@cachex/web-storage'
import Query from './Query'
import Endpoint from './endpoints/Endpoint'
import SimpleEndpoint from './endpoints/SimpleEndpoint'
@ -372,6 +372,7 @@ export default class TCGdex {
// parse, put to cache and return
const json = await resp.json()
this.cache.set(path, json, this.cacheTTL)
return json as T
}
@ -397,9 +398,13 @@ export default class TCGdex {
}
}
// export the old interfaces
export type * from './interfaces.d.ts'
export * from './models/Card'
// export the new models items and the Query
export {
Query
CardModel, CardResumeModel, Endpoint, Model, Query, SerieModel,
SerieResume as SerieResumeModel,
SetModel,
SetResumeModel, SimpleEndpoint
}

View File

@ -12,7 +12,7 @@ export function detectContext(): 'browser' | 'server' {
}
}
export const ENDPOINTS: Array<Endpoints> = [
export const ENDPOINTS: ReadonlyArray<Endpoints> = [
'cards', 'categories', 'dex-ids', 'energy-types',
'hp', 'illustrators', 'rarities', 'regulation-marks',
'retreats', 'series', 'sets', 'stages', 'suffixes',