Files
whattoplay/server/index.js
Felix Förtsch 3cac486f6f fix Steam API: transform response format and add comprehensive logging
- Backend: transform Steam API response to match frontend expectations (games/count structure)
- Frontend: map Steam game fields (appid, name, playtime_forever) to database schema (id, title, playtimeHours)
- Add detailed logging throughout request lifecycle for debugging
- Add 60-second timeout with AbortController to prevent indefinite hanging
- Fix IndexedDB constraint violation by properly transforming game data before save

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-06 22:25:04 +01:00

112 lines
2.9 KiB
JavaScript

import express from "express";
import cors from "cors";
import fetch from "node-fetch";
const app = express();
const PORT = process.env.PORT || 3000;
// Enable CORS for your PWA
app.use(
cors({
origin: process.env.ALLOWED_ORIGIN || "*",
}),
);
app.use(express.json());
// Health check
app.get("/health", (req, res) => {
res.json({ status: "ok" });
});
// Steam API refresh endpoint
app.post("/steam/refresh", async (req, res) => {
const { apiKey, steamId } = req.body;
console.log(`[Steam] Starting refresh for user: ${steamId}`);
if (!apiKey || !steamId) {
console.log("[Steam] Missing credentials");
return res.status(400).json({
error: "Missing required fields: apiKey and steamId",
});
}
try {
// Call Steam Web API
const steamUrl = `https://api.steampowered.com/IPlayerService/GetOwnedGames/v1/?key=${apiKey}&steamid=${steamId}&include_appinfo=1&include_played_free_games=1&format=json`;
console.log("[Steam] Calling Steam API...");
const response = await fetch(steamUrl);
console.log(`[Steam] Got response: ${response.status}`);
if (!response.ok) {
console.log(`[Steam] Steam API error: ${response.statusText}`);
return res.status(response.status).json({
error: "Steam API error",
message: response.statusText,
});
}
const data = await response.json();
console.log(`[Steam] Success! Games count: ${data.response?.game_count || 0}`);
// Transform Steam API response to match frontend expectations
const transformed = {
games: data.response?.games || [],
count: data.response?.game_count || 0,
};
const responseSize = JSON.stringify(transformed).length;
console.log(`[Steam] Sending response: ${responseSize} bytes, ${transformed.games.length} games`);
res.json(transformed);
console.log(`[Steam] Response sent successfully`);
} catch (error) {
console.error("[Steam] Exception:", error);
res.status(500).json({
error: "Failed to fetch games",
message: error.message,
});
}
});
// Fallback proxy for other Steam API calls
app.all("/*", async (req, res) => {
const path = req.url;
const steamUrl = `https://store.steampowered.com${path}`;
console.log(`Proxying: ${req.method} ${steamUrl}`);
try {
const response = await fetch(steamUrl, {
method: req.method,
headers: {
"User-Agent": "WhatToPlay/1.0",
Accept: "application/json",
...(req.body && { "Content-Type": "application/json" }),
},
...(req.body && { body: JSON.stringify(req.body) }),
});
const contentType = response.headers.get("content-type");
if (contentType && contentType.includes("application/json")) {
const data = await response.json();
res.json(data);
} else {
const text = await response.text();
res.send(text);
}
} catch (error) {
console.error("Proxy error:", error);
res.status(500).json({
error: "Proxy error",
message: error.message,
});
}
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});