feat: updates page and lint fixes
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Elysia, t } from "elysia"
|
||||
import { db } from "@/lib/db/index"
|
||||
import { communitySuggestions, games, user } from "@/lib/db/schema"
|
||||
import { communitySuggestions, games, user, suggestionStatusEnum } from "@/lib/db/schema"
|
||||
import { eq, and, desc } from "drizzle-orm"
|
||||
import { requireAuth, requireContributorOrAdmin } from "@/lib/auth/guard"
|
||||
|
||||
@@ -109,7 +109,7 @@ export const communitySuggestionRoutes = new Elysia({
|
||||
return { error: "You already have a pending suggestion for this field" }
|
||||
}
|
||||
|
||||
const currentValue = String((game as any)[fieldName] ?? "")
|
||||
const currentValue = String((game as Record<string, unknown>)[fieldName] ?? "")
|
||||
|
||||
const [suggestion] = await db
|
||||
.insert(communitySuggestions)
|
||||
@@ -149,9 +149,9 @@ export const communitySuggestionRoutes = new Elysia({
|
||||
async ({ params, query }) => {
|
||||
const status = query.status // optional filter
|
||||
|
||||
let conditions = [eq(communitySuggestions.gameId, params.gameId)]
|
||||
const conditions = [eq(communitySuggestions.gameId, params.gameId)]
|
||||
if (status) {
|
||||
conditions.push(eq(communitySuggestions.status, status as any))
|
||||
conditions.push(eq(communitySuggestions.status, status as typeof suggestionStatusEnum.enumValues[number]))
|
||||
}
|
||||
|
||||
const suggestions = await db
|
||||
@@ -263,7 +263,7 @@ export const communitySuggestionRoutes = new Elysia({
|
||||
|
||||
// If approved, apply the change to the game
|
||||
if (status === "approved") {
|
||||
const updateData: Record<string, any> = {}
|
||||
const updateData: Record<string, string> = {}
|
||||
updateData[suggestion.fieldName] = suggestion.proposedValue
|
||||
|
||||
await db
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
gamePlatformSupport,
|
||||
hardware,
|
||||
} from "@/lib/db/schema"
|
||||
import { ilike, or, sql, eq, and, desc, asc, inArray, gte, lte } from "drizzle-orm"
|
||||
import { ilike, or, sql, eq, and, desc, asc, inArray, gte, lte, type SQL } from "drizzle-orm"
|
||||
import { fuzzySearchTerm } from "@/lib/db/search"
|
||||
|
||||
const MAX_OFFSET = 10000
|
||||
@@ -92,11 +92,11 @@ export const gamesListingRoutes = new Elysia({ prefix: "/games/listing" }).get(
|
||||
|
||||
// ── FPS range filter (games with benchmarks in this range) ────
|
||||
if (minFps || maxFps) {
|
||||
const fpsConditions = [
|
||||
const fpsConditions: (SQL | undefined)[] = [
|
||||
eq(performanceEntries.isRemoved, false),
|
||||
minFps ? gte(performanceEntries.fpsAvg, Number(minFps)) : undefined,
|
||||
maxFps ? lte(performanceEntries.fpsAvg, Number(maxFps)) : undefined,
|
||||
].filter(Boolean) as any[]
|
||||
].filter((c): c is SQL => c !== undefined)
|
||||
|
||||
const fpsSubquery = db
|
||||
.select({ gameId: gameVersions.gameId })
|
||||
@@ -127,7 +127,7 @@ export const gamesListingRoutes = new Elysia({ prefix: "/games/listing" }).get(
|
||||
|
||||
// ── Proton / Native filter ────────────────────────────────────
|
||||
if (protonNative && ["proton", "native", "both"].includes(protonNative)) {
|
||||
const protonConditions: any[] = []
|
||||
const protonConditions: SQL[] = []
|
||||
|
||||
if (protonNative === "proton" || protonNative === "both") {
|
||||
protonConditions.push(eq(gamePlatformSupport.protonStatus, "proton"))
|
||||
@@ -148,7 +148,7 @@ export const gamesListingRoutes = new Elysia({ prefix: "/games/listing" }).get(
|
||||
// ── Anti-cheat status filter ──────────────────────────────────
|
||||
const validAcStatuses = ["supported", "unsupported", "unknown", "none"]
|
||||
if (antiCheatStatus && antiCheatStatus !== "any" && validAcStatuses.includes(antiCheatStatus)) {
|
||||
const acConditions: any[] = [
|
||||
const acConditions: SQL[] = [
|
||||
eq(gamePlatformSupport.antiCheatRelevant, true),
|
||||
eq(gamePlatformSupport.antiCheatStatus, antiCheatStatus as "none" | "supported" | "unsupported" | "unknown"),
|
||||
]
|
||||
|
||||
+3
-42
@@ -190,46 +190,7 @@ export const gameVersionsRoutes = new Elysia({ prefix: "/games/:gameId/versions"
|
||||
|
||||
// ── Game Sync Routes ────────────────────────────────────────────────
|
||||
const MAX_BULK_SYNC = 1000
|
||||
const SYNC_CONCURRENCY = 5 // Number of parallel syncs
|
||||
const SYNC_BATCH_DELAY_MS = 2000 // Delay between batches to respect rate limits (2 seconds)
|
||||
|
||||
/**
|
||||
* Process syncs sequentially with delay to avoid Steam rate limiting.
|
||||
* Steam API has aggressive rate limiting - parallel requests get blocked quickly.
|
||||
*/
|
||||
async function syncSequentially(
|
||||
gamesToSync: { id: string; steamAppId: number | null }[]
|
||||
): Promise<{ synced: number; failed: number; results: Map<string, { success: boolean; error?: string }> }> {
|
||||
let synced = 0
|
||||
let failed = 0
|
||||
const results = new Map<string, { success: boolean; error?: string }>()
|
||||
|
||||
for (let i = 0; i < gamesToSync.length; i++) {
|
||||
const game = gamesToSync[i]
|
||||
if (!game.steamAppId) continue
|
||||
|
||||
try {
|
||||
const result = await syncSteamGame(game.steamAppId, { forceRetry: true })
|
||||
if (result.success) {
|
||||
synced++
|
||||
results.set(game.id, { success: true })
|
||||
} else {
|
||||
failed++
|
||||
results.set(game.id, { success: false, error: result.error })
|
||||
}
|
||||
} catch (e) {
|
||||
failed++
|
||||
results.set(game.id, { success: false, error: String(e) })
|
||||
}
|
||||
|
||||
// Delay between syncs to avoid rate limiting
|
||||
if (i < gamesToSync.length - 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve, SYNC_BATCH_DELAY_MS))
|
||||
}
|
||||
}
|
||||
|
||||
return { synced, failed, results }
|
||||
}
|
||||
|
||||
export const gameSyncRoutes = new Elysia({ prefix: "/games" })
|
||||
// Bulk sync with streaming progress (defined before /:gameId/sync to avoid route conflict)
|
||||
@@ -285,7 +246,8 @@ export const gameSyncRoutes = new Elysia({ prefix: "/games" })
|
||||
const encoder = new TextEncoder()
|
||||
const stream = new ReadableStream({
|
||||
async start(controller) {
|
||||
const send = (data: any) => {
|
||||
type ProgressEvent = { type: string; current?: number; total: number; synced: number; failed: number; currentGame?: string | null }
|
||||
const send = (data: ProgressEvent) => {
|
||||
controller.enqueue(encoder.encode(JSON.stringify(data) + "\n"))
|
||||
}
|
||||
|
||||
@@ -294,7 +256,6 @@ export const gameSyncRoutes = new Elysia({ prefix: "/games" })
|
||||
|
||||
let synced = 0
|
||||
let failed = 0
|
||||
const batchSize = SYNC_CONCURRENCY
|
||||
|
||||
// Process syncs sequentially with delay to avoid rate limiting
|
||||
for (let i = 0; i < gamesToSync.length; i++) {
|
||||
@@ -305,7 +266,7 @@ export const gameSyncRoutes = new Elysia({ prefix: "/games" })
|
||||
const result = await syncSteamGame(game.steamAppId, { forceRetry: true })
|
||||
if (result.success) synced++
|
||||
else failed++
|
||||
} catch (e) {
|
||||
} catch {
|
||||
failed++
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Elysia } from "elysia";
|
||||
import { db } from "@/lib/db/index";
|
||||
import { games, gamePlatformSupport, performanceEntries, gameVersions } from "@/lib/db/schema";
|
||||
import { games, gamePlatformSupport, performanceEntries, gameVersions, playabilityStatusEnum } from "@/lib/db/schema";
|
||||
import { eq, and, avg, count, sql } from "drizzle-orm";
|
||||
import { requireContributorOrAdmin } from "@/lib/auth/guard";
|
||||
|
||||
@@ -95,7 +95,7 @@ export async function recalculatePlayability(gameId: string): Promise<{
|
||||
await db
|
||||
.update(gamePlatformSupport)
|
||||
.set({
|
||||
playabilityStatus: status as any,
|
||||
playabilityStatus: status as typeof playabilityStatusEnum.enumValues[number],
|
||||
playabilityCalculatedAt: new Date(),
|
||||
})
|
||||
.where(
|
||||
@@ -111,13 +111,13 @@ export async function recalculatePlayability(gameId: string): Promise<{
|
||||
|
||||
// Update aggregate game-level playability (worst of all devices)
|
||||
const priority = { unplayable: 0, needs_tweaks: 1, playable: 2, great: 3, unknown: 4 };
|
||||
let worstStatus: string = "unknown";
|
||||
let worstStatus: typeof playabilityStatusEnum.enumValues[number] = "unknown";
|
||||
for (const r of results) {
|
||||
if (
|
||||
priority[r.playabilityStatus as keyof typeof priority] <
|
||||
priority[worstStatus as keyof typeof priority]
|
||||
) {
|
||||
worstStatus = r.playabilityStatus;
|
||||
worstStatus = r.playabilityStatus as typeof playabilityStatusEnum.enumValues[number];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ export async function recalculatePlayability(gameId: string): Promise<{
|
||||
await db
|
||||
.update(games)
|
||||
.set({
|
||||
playabilityStatus: worstStatus as any,
|
||||
playabilityStatus: worstStatus as typeof playabilityStatusEnum.enumValues[number],
|
||||
playabilityCalculatedAt: new Date(),
|
||||
})
|
||||
.where(eq(games.id, gameId));
|
||||
@@ -174,7 +174,7 @@ export const playabilityRoutes = new Elysia({ prefix: "/playability" })
|
||||
if (hardwareSlug) {
|
||||
await db
|
||||
.update(gamePlatformSupport)
|
||||
.set({ playabilityStatus: status as any, playabilityOverride: true })
|
||||
.set({ playabilityStatus: status as typeof playabilityStatusEnum.enumValues[number], playabilityOverride: true })
|
||||
.where(
|
||||
and(
|
||||
eq(gamePlatformSupport.gameId, params.gameId),
|
||||
@@ -184,7 +184,7 @@ export const playabilityRoutes = new Elysia({ prefix: "/playability" })
|
||||
} else {
|
||||
await db
|
||||
.update(games)
|
||||
.set({ playabilityStatus: status as any, playabilityOverride: true })
|
||||
.set({ playabilityStatus: status as typeof playabilityStatusEnum.enumValues[number], playabilityOverride: true })
|
||||
.where(eq(games.id, params.gameId));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { eq } from "drizzle-orm"
|
||||
// In-memory cache for reviews (key -> { data, expires })
|
||||
const reviewCache = new Map<
|
||||
string,
|
||||
{ data: any; expires: number }
|
||||
{ data: SteamReviewResponse; expires: number }
|
||||
>()
|
||||
|
||||
const CACHE_TTL = 60 * 60 * 1000 // 1 hour
|
||||
@@ -100,7 +100,7 @@ export const steamReviewRoutes = new Elysia({ prefix: "/steam-reviews" })
|
||||
reviewCache.set(cacheKey, { data: slicedData, expires: Date.now() + CACHE_TTL })
|
||||
|
||||
return slicedData
|
||||
} catch (error) {
|
||||
} catch {
|
||||
set.status = 502
|
||||
return { error: "Steam review API unavailable" }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user