feat(plugin): plugin_get proxy + typed library-panel fetch/cache
This commit is contained in:
@@ -166,4 +166,7 @@ export const checkPairStatus = callable<[token: string, baseUrl?: string], {
|
||||
apiKey?: string
|
||||
keyName?: string
|
||||
error?: string
|
||||
}>("check_pair_status")
|
||||
}>("check_pair_status")
|
||||
|
||||
// ── Plugin API Proxy ────────────────────────────────────────────
|
||||
export const pluginGet = callable<[path: string, baseUrl?: string], Record<string, unknown> & { status?: number; error?: string }>("plugin_get")
|
||||
@@ -0,0 +1,74 @@
|
||||
import { pluginGet } from "./api"
|
||||
|
||||
export interface PluginEntry {
|
||||
id: string
|
||||
hardwareSlug: string
|
||||
fpsAvg: number
|
||||
fpsLow: number | null
|
||||
fpsOnePercentLow: number | null
|
||||
fpsHigh: number | null
|
||||
upscalerType: string
|
||||
frameGenMethod: string
|
||||
protonVersion: string | null
|
||||
osVersion: string | null
|
||||
tdpWatts: number | null
|
||||
settingsJson: unknown
|
||||
upvotes: number
|
||||
isPinned: boolean
|
||||
createdAt: string
|
||||
userName: string | null
|
||||
userImage: string | null
|
||||
}
|
||||
|
||||
export interface PluginGameResponse {
|
||||
game: { id: string; steamAppId: number | null; title: string; slug: string | null } | null
|
||||
estFps: { avg: number; low: number | null; onePct: number | null; high: number | null; count: number } | null
|
||||
topEntries: PluginEntry[]
|
||||
recentEntries: PluginEntry[]
|
||||
error?: string
|
||||
}
|
||||
|
||||
export interface PluginDeviceRow {
|
||||
slug: string
|
||||
name: string
|
||||
count: number
|
||||
}
|
||||
|
||||
// Tiny per-appId cache (1h TTL)
|
||||
interface CacheEntry { value: PluginGameResponse; expires: number }
|
||||
const cache = new Map<string, CacheEntry>()
|
||||
const TTL_MS = 60 * 60 * 1000
|
||||
const settingsRef: { baseUrl: string } = { baseUrl: "https://deckyvault.xyz" }
|
||||
|
||||
export function setPluginApiBaseUrl(url: string) {
|
||||
settingsRef.baseUrl = url || "https://deckyvault.xyz"
|
||||
}
|
||||
|
||||
export async function fetchPluginGame(
|
||||
steamAppId: number,
|
||||
hardware: string | null,
|
||||
limit: number,
|
||||
): Promise<PluginGameResponse> {
|
||||
const key = `${steamAppId}|${hardware ?? "all"}|${limit}`
|
||||
const hit = cache.get(key)
|
||||
if (hit && hit.expires > Date.now()) return hit.value
|
||||
|
||||
const path = `/plugin/game/${steamAppId}?limit=${limit}${hardware ? `&hardware=${encodeURIComponent(hardware)}` : ""}`
|
||||
const raw = await pluginGet(path, settingsRef.baseUrl)
|
||||
const value = raw as unknown as PluginGameResponse
|
||||
cache.set(key, { value, expires: Date.now() + TTL_MS })
|
||||
return value
|
||||
}
|
||||
|
||||
export async function fetchPluginDevices(steamAppId: number): Promise<PluginDeviceRow[]> {
|
||||
const raw = await pluginGet(`/plugin/game/${steamAppId}/devices`, settingsRef.baseUrl)
|
||||
if (raw.error) return []
|
||||
return (raw.devices as PluginDeviceRow[]) ?? []
|
||||
}
|
||||
|
||||
export function clearPluginCache(steamAppId?: number) {
|
||||
if (steamAppId == null) { cache.clear(); return }
|
||||
for (const k of cache.keys()) {
|
||||
if (k.startsWith(`${steamAppId}|`)) cache.delete(k)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user