import { Request, Response, Express } from "express"; import { supabase } from "./supabase.js"; import { GameDevAPIs } from "./game-dev-apis.js"; import { requireAuth } from "./auth"; import crypto from "crypto"; // Game Marketplace Routes export function registerGameRoutes(app: Express): void { // ========== GAME MARKETPLACE ========== // Get marketplace items app.get("/api/game/marketplace", async (req: Request, res: Response) => { try { const { category, platform, search, sort = "newest", limit = 20, offset = 0 } = req.query; let query = supabase.from("game_items").select("*"); if (category && category !== "all") { query = query.eq("type", category as string); } if (platform && platform !== "all") { query = query.eq("platform", platform as string); } if (search) { query = query.or(`name.ilike.%${search}%,description.ilike.%${search}%`); } // Sorting switch(sort) { case "popular": query = query.order("purchase_count", { ascending: false }); break; case "price-low": query = query.order("price", { ascending: true }); break; case "price-high": query = query.order("price", { ascending: false }); break; default: query = query.order("created_at", { ascending: false }); } query = query.range(Number(offset), Number(offset) + Number(limit) - 1); const { data, error } = await query; if (error) throw error; res.json(data); } catch (err: any) { res.status(500).json({ error: err.message }); } }); // Get item details app.get("/api/game/marketplace/:itemId", async (req: Request, res: Response) => { try { const { data, error } = await supabase .from("game_items") .select("*") .eq("id", req.params.itemId) .single(); if (error) throw error; res.json(data); } catch (err: any) { res.status(404).json({ error: "Item not found" }); } }); // Purchase marketplace item app.post("/api/game/marketplace/purchase", requireAuth, async (req: Request, res: Response) => { try { const { itemId, price } = req.body; const userId = (req.session as any)?.userId; if (!userId) return res.status(401).json({ error: "Unauthorized" }); // Check user wallet balance const { data: wallet, error: walletError } = await supabase .from("game_wallets") .select("id, balance") .eq("user_id", userId) .single(); if (walletError) throw walletError; if (!wallet || wallet.balance < price) { return res.status(400).json({ error: "Insufficient balance" }); } // Create transaction const transactionId = crypto.randomUUID(); const { error: transError } = await supabase .from("game_transactions") .insert({ id: transactionId, user_id: userId, wallet_id: wallet.id, type: "purchase", amount: price, currency: "LP", platform: "game-marketplace", status: "completed", metadata: { item_id: itemId } }); if (transError) throw transError; // Update wallet balance await supabase .from("game_wallets") .update({ balance: wallet.balance - price }) .eq("user_id", userId); // Update item purchase count await supabase.rpc("increment_purchase_count", { item_id: itemId }); res.status(201).json({ success: true, transaction_id: transactionId, new_balance: wallet.balance - price }); } catch (err: any) { res.status(500).json({ error: err.message }); } }); // ========== MOD WORKSHOP ========== // Get mods app.get("/api/game/workshop", async (req: Request, res: Response) => { try { const { category, game, search, sort = "trending", limit = 20, offset = 0 } = req.query; let query = supabase.from("game_mods").select("*"); if (category && category !== "all") { query = query.eq("category", category as string); } if (game && game !== "all") { query = query.or(`game.eq.${game},game.eq.All Games`); } if (search) { query = query.or(`name.ilike.%${search}%,author.ilike.%${search}%`); } // Sorting switch(sort) { case "popular": query = query.order("download_count", { ascending: false }); break; case "rating": query = query.order("rating", { ascending: false }); break; case "trending": query = query.order("like_count", { ascending: false }); break; default: query = query.order("created_at", { ascending: false }); } query = query.eq("status", "approved").range(Number(offset), Number(offset) + Number(limit) - 1); const { data, error } = await query; if (error) throw error; res.json(data); } catch (err: any) { res.status(500).json({ error: err.message }); } }); // Upload mod app.post("/api/game/workshop/upload", requireAuth, async (req: Request, res: Response) => { try { const { name, description, category, game, version, fileSize } = req.body; const userId = (req.session as any)?.userId; if (!userId) return res.status(401).json({ error: "Unauthorized" }); const modId = crypto.randomUUID(); const { error } = await supabase.from("game_mods").insert({ id: modId, name, description, category, game, version, author_id: userId, file_size: fileSize, status: "reviewing", // Under review by default rating: 0, review_count: 0, download_count: 0, like_count: 0, view_count: 0 }); if (error) throw error; res.status(201).json({ success: true, mod_id: modId, message: "Mod uploaded successfully and is under review" }); } catch (err: any) { res.status(500).json({ error: err.message }); } }); // Rate mod app.post("/api/game/workshop/:modId/rate", requireAuth, async (req: Request, res: Response) => { try { const { modId } = req.params; const { rating, review } = req.body; const userId = (req.session as any)?.userId; if (!userId) return res.status(401).json({ error: "Unauthorized" }); if (rating < 1 || rating > 5) { return res.status(400).json({ error: "Rating must be 1-5" }); } const { error } = await supabase.from("game_mod_reviews").insert({ mod_id: modId, user_id: userId, rating, review: review || null }); if (error) throw error; // Update mod rating average const { data: reviews } = await supabase .from("game_mod_reviews") .select("rating") .eq("mod_id", modId); if (reviews && reviews.length > 0) { const avgRating = reviews.reduce((sum: number, r: any) => sum + r.rating, 0) / reviews.length; await supabase .from("game_mods") .update({ rating: avgRating, review_count: reviews.length }) .eq("id", modId); } res.status(201).json({ success: true }); } catch (err: any) { res.status(500).json({ error: err.message }); } }); // Download mod app.post("/api/game/workshop/:modId/download", requireAuth, async (req: Request, res: Response) => { try { const { modId } = req.params; const userId = (req.session as any)?.userId; if (!userId) return res.status(401).json({ error: "Unauthorized" }); // Increment download count await supabase.rpc("increment_mod_downloads", { mod_id: modId }); // Record download await supabase.from("game_mod_downloads").insert({ mod_id: modId, user_id: userId, downloaded_at: new Date() }); res.json({ success: true, download_url: `/api/game/workshop/${modId}/file` }); } catch (err: any) { res.status(500).json({ error: err.message }); } }); // ========== GAME STREAMING ========== // Get streams app.get("/api/game/streams", async (req: Request, res: Response) => { try { const { platform, live = false, limit = 20 } = req.query; let query = supabase.from("game_streams").select("*"); if (platform && platform !== "all") { query = query.eq("platform", platform as string); } if (live) { query = query.eq("is_live", true); } query = query.order("created_at", { ascending: false }).limit(Number(limit)); const { data, error } = await query; if (error) throw error; res.json(data); } catch (err: any) { res.status(500).json({ error: err.message }); } }); // Create stream event app.post("/api/game/streams", requireAuth, async (req: Request, res: Response) => { try { const { title, platform, game, description, streamUrl } = req.body; const userId = (req.session as any)?.userId; if (!userId) return res.status(401).json({ error: "Unauthorized" }); const { error } = await supabase.from("game_streams").insert({ user_id: userId, title, platform, game, description, stream_url: streamUrl, is_live: true, viewer_count: 0, start_time: new Date() }); if (error) throw error; res.status(201).json({ success: true }); } catch (err: any) { res.status(500).json({ error: err.message }); } }); // ========== GAME WALLET & TRANSACTIONS ========== // Get user wallet app.get("/api/game/wallet", requireAuth, async (req: Request, res: Response) => { try { const userId = (req.session as any)?.userId; if (!userId) return res.status(401).json({ error: "Unauthorized" }); const { data, error } = await supabase .from("game_wallets") .select("*") .eq("user_id", userId) .single(); if (error && error.code !== 'PGRST116') throw error; if (!data) { // Create wallet if doesn't exist const { data: newWallet } = await supabase .from("game_wallets") .insert({ user_id: userId, balance: 5000 }) .select() .single(); return res.json(newWallet); } res.json(data); } catch (err: any) { res.status(500).json({ error: err.message }); } }); // Get transaction history app.get("/api/game/transactions", requireAuth, async (req: Request, res: Response) => { try { const userId = (req.session as any)?.userId; if (!userId) return res.status(401).json({ error: "Unauthorized" }); const { limit = 50 } = req.query; const { data, error } = await supabase .from("game_transactions") .select("*") .eq("user_id", userId) .order("created_at", { ascending: false }) .limit(Number(limit)); if (error) throw error; res.json(data); } catch (err: any) { res.status(500).json({ error: err.message }); } }); // ========== PLAYER PROFILES & ACHIEVEMENTS ========== // Get player profile app.get("/api/game/profiles/:userId", async (req: Request, res: Response) => { try { const { userId } = req.params; const { data, error } = await supabase .from("game_profiles") .select("*") .eq("user_id", userId) .single(); if (error) throw error; res.json(data); } catch (err: any) { res.status(500).json({ error: err.message }); } }); // Get achievements app.get("/api/game/achievements/:userId", async (req: Request, res: Response) => { try { const { userId } = req.params; const { data, error } = await supabase .from("game_achievements") .select("*") .eq("user_id", userId) .order("unlocked_at", { ascending: false }); if (error) throw error; res.json(data); } catch (err: any) { res.status(500).json({ error: err.message }); } }); // Grant achievement app.post("/api/game/achievements/grant", requireAuth, async (req: Request, res: Response) => { try { const { achievementId } = req.body; const userId = (req.session as any)?.userId; if (!userId) return res.status(401).json({ error: "Unauthorized" }); const { error } = await supabase.from("game_achievements").insert({ user_id: userId, achievement_id: achievementId, unlocked_at: new Date() }); if (error) throw error; res.status(201).json({ success: true }); } catch (err: any) { res.status(500).json({ error: err.message }); } }); // ========== OAUTH GAME LINKING ========== // Link game account (Minecraft, Steam, etc.) app.post("/api/game/oauth/link/:provider", requireAuth, async (req: Request, res: Response) => { try { const { provider } = req.params; const { accountId, accountName, metadata } = req.body; const userId = (req.session as any)?.userId; if (!userId) return res.status(401).json({ error: "Unauthorized" }); const { error } = await supabase.from("game_accounts").insert({ user_id: userId, platform: provider, account_id: accountId, username: accountName, verified: true, metadata: metadata || {} }); if (error) throw error; res.status(201).json({ success: true }); } catch (err: any) { res.status(500).json({ error: err.message }); } }); // Get linked accounts app.get("/api/game/accounts", requireAuth, async (req: Request, res: Response) => { try { const userId = (req.session as any)?.userId; if (!userId) return res.status(401).json({ error: "Unauthorized" }); const { data, error } = await supabase .from("game_accounts") .select("*") .eq("user_id", userId); if (error) throw error; res.json(data); } catch (err: any) { res.status(500).json({ error: err.message }); } }); console.log("✓ Game feature routes registered"); }