mirror of
https://github.com/tcgdex/javascript-sdk.git
synced 2025-04-22 02:42:08 +00:00
feat: Add CacheX for cache management (#281)
This commit is contained in:
parent
e501faa823
commit
1f3aae5401
54
package-lock.json
generated
54
package-lock.json
generated
@ -1,14 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "@tcgdex/sdk",
|
"name": "@tcgdex/sdk",
|
||||||
"version": "2.6.0-beta.1",
|
"version": "2.6.0-beta.3",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@tcgdex/sdk",
|
"name": "@tcgdex/sdk",
|
||||||
"version": "2.6.0-beta.1",
|
"version": "2.6.0-beta.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@cachex/memory": "^1.0.0",
|
||||||
|
"@cachex/web-storage": "^1.0.1",
|
||||||
"@dzeio/object-util": "^1",
|
"@dzeio/object-util": "^1",
|
||||||
"isomorphic-unfetch": "^3"
|
"isomorphic-unfetch": "^3"
|
||||||
},
|
},
|
||||||
@ -1723,6 +1725,30 @@
|
|||||||
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
|
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@cachex/core": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cachex/core/-/core-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-JZMGqh2mEAB1JqX2A7yMk6FwGMEoGTjw/Hn5UcqWXUq/Etl2cl8Z6xFUraAN9bv7wX3tTwWol/mh5Ej34to8ng==",
|
||||||
|
"dependencies": {
|
||||||
|
"@dzeio/object-util": "^1.8.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cachex/memory": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cachex/memory/-/memory-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-x/oLaj9ZbwCd4Z+3CA20kPd0mRchNFYt2VMz7vlCczWrhX5Lk1b6Z9xUFWMHpjEb2x1G9K194R+vC5qyj4QslQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@cachex/core": "^1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cachex/web-storage": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cachex/web-storage/-/web-storage-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-E8Xa9qDZgNgr+lcj3eixowg7PH2CVZbp3huuoc5xVVTtwYrZi5YqbHBG12yG3r6C6Fts/2Yoq6cbVBSm6c8VRA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@cachex/core": "^1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@dzeio/config": {
|
"node_modules/@dzeio/config": {
|
||||||
"version": "1.1.12",
|
"version": "1.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/@dzeio/config/-/config-1.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/@dzeio/config/-/config-1.1.12.tgz",
|
||||||
@ -10384,6 +10410,30 @@
|
|||||||
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
|
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@cachex/core": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cachex/core/-/core-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-JZMGqh2mEAB1JqX2A7yMk6FwGMEoGTjw/Hn5UcqWXUq/Etl2cl8Z6xFUraAN9bv7wX3tTwWol/mh5Ej34to8ng==",
|
||||||
|
"requires": {
|
||||||
|
"@dzeio/object-util": "^1.8.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@cachex/memory": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cachex/memory/-/memory-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-x/oLaj9ZbwCd4Z+3CA20kPd0mRchNFYt2VMz7vlCczWrhX5Lk1b6Z9xUFWMHpjEb2x1G9K194R+vC5qyj4QslQ==",
|
||||||
|
"requires": {
|
||||||
|
"@cachex/core": "^1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@cachex/web-storage": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cachex/web-storage/-/web-storage-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-E8Xa9qDZgNgr+lcj3eixowg7PH2CVZbp3huuoc5xVVTtwYrZi5YqbHBG12yG3r6C6Fts/2Yoq6cbVBSm6c8VRA==",
|
||||||
|
"requires": {
|
||||||
|
"@cachex/core": "^1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@dzeio/config": {
|
"@dzeio/config": {
|
||||||
"version": "1.1.12",
|
"version": "1.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/@dzeio/config/-/config-1.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/@dzeio/config/-/config-1.1.12.tgz",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tcgdex/sdk",
|
"name": "@tcgdex/sdk",
|
||||||
"version": "2.6.0-beta.3",
|
"version": "2.6.0-beta.4",
|
||||||
"main": "./dist/tcgdex.node.js",
|
"main": "./dist/tcgdex.node.js",
|
||||||
"module": "./dist/tcgdex.node.mjs",
|
"module": "./dist/tcgdex.node.mjs",
|
||||||
"types": "./dist/tcgdex.node.d.ts",
|
"types": "./dist/tcgdex.node.d.ts",
|
||||||
@ -53,6 +53,8 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@cachex/memory": "^1",
|
||||||
|
"@cachex/web-storage": "^1",
|
||||||
"@dzeio/object-util": "^1",
|
"@dzeio/object-util": "^1",
|
||||||
"isomorphic-unfetch": "^3"
|
"isomorphic-unfetch": "^3"
|
||||||
},
|
},
|
||||||
|
@ -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
|
|
||||||
}
|
|
109
src/Psr/SimpleCache/CacheInterface.d.ts
vendored
109
src/Psr/SimpleCache/CacheInterface.d.ts
vendored
@ -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
|
|
||||||
}
|
|
@ -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}`
|
|
||||||
}
|
|
||||||
}
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
import type CacheInterface from './Psr/SimpleCache/CacheInterface'
|
import type CacheInterface from '@cachex/core'
|
||||||
import LocalStorageCache from './Psr/SimpleCache/LocalStorageCache'
|
import LocalStorageCache from '@cachex/web-storage'
|
||||||
import MemoryCache from './Psr/SimpleCache/MemoryCache'
|
import MemoryCache from '@cachex/memory'
|
||||||
import Query from './Query'
|
import Query from './Query'
|
||||||
import Endpoint from './endpoints/Endpoint'
|
import Endpoint from './endpoints/Endpoint'
|
||||||
import SimpleEndpoint from './endpoints/SimpleEndpoint'
|
import SimpleEndpoint from './endpoints/SimpleEndpoint'
|
||||||
@ -402,4 +402,3 @@ export * from './models/Card'
|
|||||||
export {
|
export {
|
||||||
Query
|
Query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user