mirror of
https://github.com/AeThex-Corporation/AeThex-OS.git
synced 2026-04-17 22:27:19 +00:00
- Create server/auth.ts with requireAuth, optionalAuth, requireAdmin middleware - Fix os.tsx: add Target/Check imports, fix useLayout->usePlatformLayout, fix achievements types - Fix game-routes.ts: add all Request/Response types, fix session access - Fix revenue.ts: org_id -> organization_id - Fix votes.ts: currentSplit scope, created_by type - Fix dashboard.ts: remove unsupported .distinct() method - Fix game-dev-apis.ts: header/body type assertions - Upgrade api/execute.ts: add Python simulation, JSON validation, HTML/CSS passthrough - Upgrade app-registry.ts: full implementation with 15 apps, RBAC, categories - Clean up Java heap error logs
488 lines
14 KiB
TypeScript
488 lines
14 KiB
TypeScript
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");
|
|
}
|