/** * @file About route providing API version and release information. * @copyright nhcarrigan * @license Naomi's Public License * @author Naomi Carrigan */ /* eslint-disable stylistic/max-len -- URL cannot be shortened */ /* eslint-disable require-atomic-updates -- Simple cache; race condition is acceptable */ import { Hono } from "hono"; import type { AboutResponse, GiteaRelease } from "@elysium/types"; // eslint-disable-next-line capitalized-comments -- v8 ignore /* v8 ignore next -- @preserve */ const apiVersion = process.env.npm_package_version ?? "unknown"; const giteaReleasesUrl = "https://git.nhcarrigan.com/api/v1/repos/nhcarrigan/elysium/releases"; const cacheTtlMs = 5 * 60 * 1000; interface ReleasesCache { data: Array; timestamp: number; } let releasesCache: ReleasesCache = { data: [], timestamp: 0 }; const fetchReleases = async(): Promise> => { const now = Date.now(); if (releasesCache.data.length > 0 && now - releasesCache.timestamp < cacheTtlMs) { return releasesCache.data; } try { const response = await fetch(giteaReleasesUrl); if (!response.ok) { return releasesCache.data; } const rawData: unknown = await response.json(); /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- External API response */ const data = rawData as Array; releasesCache = { data: data, timestamp: now }; return releasesCache.data; } catch { return releasesCache.data; } }; const aboutRouter = new Hono(); aboutRouter.get("/", async(context) => { const releases = await fetchReleases(); const body: AboutResponse = { apiVersion, releases, }; return context.json(body); }); export { aboutRouter };