import { readFile, existsSync } from 'fs' import { join } from 'path' import { promisify } from 'util' const readFileAsync = promisify(readFile) // CDragon base URL for fallback const CDRAGON_BASE = 'https://raw.communitydragon.org/' // Cache directory - can be configured via environment variable // Default to dev/cdragon for development const getCacheDir = () => { if (process.env.CDRAGON_CACHE_DIR) { return process.env.CDRAGON_CACHE_DIR } // Default to dev/cdragon relative to project root return join(process.cwd(), '..', 'dev', 'data', 'cdragon') } /** * Get the current patch from the patch.txt file or fallback to 'latest' * Converts patch format for CDragon: "16.4.1" -> "16.4" */ async function getCurrentPatch(): Promise { const cacheDir = getCacheDir() const patchFile = join(cacheDir, 'latest', 'patch.txt') if (existsSync(patchFile)) { const patch = await readFileAsync(patchFile, 'utf-8') const trimmedPatch = patch.trim() // Convert patch format for CDragon: "16.4.1" -> "16.4" return trimmedPatch.split('.').slice(0, 2).join('.') } // Fallback to 'latest' if no patch file exists return 'latest' } /** * Cached CDragon data types */ interface CDragonCacheOptions { patch?: string } /** * Fetch data from local cache with CDragon fallback */ async function fetchFromCache( assetName: string, cdragonPath: string, options?: CDragonCacheOptions ): Promise { const cacheDir = getCacheDir() const patch = options?.patch || (await getCurrentPatch()) const cachePath = join(cacheDir, patch, assetName) // Try to read from cache first if (existsSync(cachePath)) { try { const data = await readFileAsync(cachePath, 'utf-8') return JSON.parse(data) as T } catch (error) { console.error(`Error reading cache file ${cachePath}:`, error) } } // Fallback to CDragon console.log(`Cache miss for ${assetName}, fetching from CDragon...`) const url = `${CDRAGON_BASE}${patch}/${cdragonPath}` const response = await fetch(url) if (!response.ok) { throw new Error(`Failed to fetch ${assetName} from CDragon: ${response.status}`) } return (await response.json()) as T } /** * Get items data from cache */ async function getItems(patch?: string): Promise { return fetchFromCache( 'items.json', 'plugins/rcp-be-lol-game-data/global/default/v1/items.json', { patch } ) } /** * Get perks (runes) data from cache */ async function getPerks(patch?: string): Promise { return fetchFromCache( 'perks.json', 'plugins/rcp-be-lol-game-data/global/default/v1/perks.json', { patch } ) } /** * Get perk styles data from cache */ async function getPerkStyles(patch?: string): Promise { return fetchFromCache( 'perkstyles.json', 'plugins/rcp-be-lol-game-data/global/default/v1/perkstyles.json', { patch } ) } /** * Get summoner spells data from cache */ async function getSummonerSpells(patch?: string): Promise { return fetchFromCache( 'summoner-spells.json', 'plugins/rcp-be-lol-game-data/global/default/v1/summoner-spells.json', { patch } ) } /** * Get champion summary data from cache */ async function getChampionSummary(patch?: string): Promise { return fetchFromCache( 'champion-summary.json', 'plugins/rcp-be-lol-game-data/global/default/v1/champion-summary.json', { patch } ) } // Type definitions for CDragon data interface CDragonItem { id: number name: string iconPath: string description?: string plaintext?: string into?: number[] from?: number[] gold?: { base: number total: number sell: number } } interface CDragonPerk { id: number name: string iconPath: string shortDesc?: string longDesc?: string } interface CDragonPerkStyle { id: number name: string iconPath: string slots: Array<{ type: string perks: number[] }> } interface CDragonPerkStyles { styles: CDragonPerkStyle[] } interface CDragonSummonerSpell { id: number name: string iconPath: string description?: string } interface CDragonChampionSummary { id: number name: string alias: string squarePortraitPath: string roles?: string[] } export { getItems, getPerks, getPerkStyles, getSummonerSpells, getChampionSummary, getCurrentPatch, CDRAGON_BASE } export type { CDragonItem, CDragonPerk, CDragonPerkStyle, CDragonPerkStyles, CDragonSummonerSpell, CDragonChampionSummary }