refactor: convert to bun workspaces monorepo

- Move web app into apps/web/
- Create packages/shared/ with shared types
- Create plugins/decky-vault/ scaffold
- Root package.json manages workspaces only
This commit is contained in:
2026-06-28 05:20:28 +08:00
parent c4bede20d4
commit cd72b7a948
345 changed files with 488 additions and 126 deletions
+174
View File
@@ -0,0 +1,174 @@
/**
* Version Fetcher Test API
*
* Two endpoints:
* 1. GET /api/games/:gameId/test-version-fetchers
* Uses DB game ID (UUID or numeric Steam App ID) to look up the game,
* then runs all strategies.
*
* 2. GET /api/version-test?steamAppId=730
* Runs all strategies directly against a Steam App ID — no DB lookup needed.
* This is the preferred testing endpoint.
*/
import { Elysia, t } from "elysia"
import { db } from "@/lib/db/index"
import { games } from "@/lib/db/schema"
import { eq } from "drizzle-orm"
import { ALL_STRATEGIES } from "@/lib/version-fetchers/index"
async function resolveGame(gameId: string): Promise<{
steamAppId: number
title: string | null
dbId: string | null
} | null> {
// Try numeric (Steam App ID) first
const isNumeric = /^\d+$/.test(gameId)
const numId = isNumeric ? Number(gameId) : null
if (numId) {
// Look up by Steam App ID in DB
const [game] = await db
.select({ id: games.id, steamAppId: games.steamAppId, title: games.title })
.from(games)
.where(eq(games.steamAppId, numId))
.limit(1)
return {
steamAppId: numId,
title: game?.title ?? null,
dbId: game?.id ?? null,
}
}
// Try UUID
const [game] = await db
.select({ id: games.id, steamAppId: games.steamAppId, title: games.title })
.from(games)
.where(eq(games.id, gameId))
.limit(1)
if (!game || game.steamAppId === null) return null
return {
steamAppId: game.steamAppId,
title: game.title,
dbId: game.id,
}
}
// ── Nested route: /api/games/:gameId/test-version-fetchers ──────
export const versionTestRoutes = new Elysia({
prefix: "/games/:gameId",
detail: { tags: ["Games"] },
}).get(
"/test-version-fetchers",
async ({ params, query, set }) => {
// Support direct steamAppId override via query param
let steamAppId: number
let title: string | null = null
let dbId: string | null = null
if (query.steamAppId) {
// Use provided Steam App ID directly
steamAppId = Number(query.steamAppId)
} else {
const resolved = await resolveGame(params.gameId)
if (!resolved) {
set.status = 404
return { error: "Game not found. Try passing ?steamAppId=730 directly." }
}
steamAppId = resolved.steamAppId
title = resolved.title
dbId = resolved.dbId
}
// Run all strategies
const results = await Promise.all(
ALL_STRATEGIES.map(async (s) => {
const result = await s.fn(steamAppId)
return {
strategy: s.name,
versionString: result.versionString,
buildId: result.buildId,
success: result.success,
error: result.error ?? null,
}
}),
)
// Determine best
const withVersion = results.find((r) => r.versionString)
const withBuild = results.find((r) => r.buildId)
const best = withVersion ?? withBuild ?? null
return {
game: {
id: dbId ?? params.gameId,
title: title ?? `Steam App ${steamAppId}`,
steamAppId,
},
results,
best: best
? {
strategy: best.strategy,
versionString: best.versionString,
buildId: best.buildId,
}
: null,
}
},
{
params: t.Object({ gameId: t.String() }),
query: t.Object({
steamAppId: t.Optional(t.String()),
}),
},
)
// ── Standalone route: /api/version-test?steamAppId=730 ──────────
export const standaloneVersionTestRoutes = new Elysia({
prefix: "/version-test",
detail: { tags: ["Games"] },
}).get(
"/",
async ({ query }) => {
const steamAppId = Number(query.steamAppId)
if (!steamAppId || isNaN(steamAppId)) {
return { error: "steamAppId query parameter is required (e.g., ?steamAppId=730)" }
}
const results = await Promise.all(
ALL_STRATEGIES.map(async (s) => {
const result = await s.fn(steamAppId)
return {
strategy: s.name,
versionString: result.versionString,
buildId: result.buildId,
success: result.success,
error: result.error ?? null,
}
}),
)
const withVersion = results.find((r) => r.versionString)
const withBuild = results.find((r) => r.buildId)
const best = withVersion ?? withBuild ?? null
return {
steamAppId,
results,
best: best
? {
strategy: best.strategy,
versionString: best.versionString,
buildId: best.buildId,
}
: null,
}
},
{
query: t.Object({
steamAppId: t.String(),
}),
},
)