diff --git a/api/games/game-auth.ts b/api/games/game-auth.ts new file mode 100644 index 00000000..46e2b5b3 --- /dev/null +++ b/api/games/game-auth.ts @@ -0,0 +1,123 @@ +import type { VercelRequest, VercelResponse } from "@vercel/node"; +import { createClient } from "@supabase/supabase-js"; + +const supabase = createClient( + process.env.SUPABASE_URL || "", + process.env.SUPABASE_SERVICE_ROLE || "", +); + +export interface GameAuthRequest { + game: "unity" | "unreal" | "godot" | string; + player_id: string; + player_name: string; + auth_token?: string; // Optional existing AeThex auth token + device_id?: string; + platform?: string; // "PC", "Mobile", "Console", etc. +} + +export default async function handler(req: VercelRequest, res: VercelResponse) { + // Allow both GET (for testing) and POST (for actual auth) + if (req.method !== "POST" && req.method !== "GET") { + res.setHeader("Allow", "POST, GET"); + return res.status(405).json({ error: "Method not allowed" }); + } + + try { + const { game, player_id, player_name, auth_token, device_id, platform } = + req.method === "POST" ? req.body : req.query; + + if (!game || !player_id || !player_name) { + return res.status(400).json({ + error: "Missing required fields: game, player_id, player_name", + }); + } + + const validGames = ["unity", "unreal", "godot", "roblox", "custom"]; + if (!validGames.includes(String(game))) { + return res.status(400).json({ + error: `Invalid game. Must be one of: ${validGames.join(", ")}`, + }); + } + + const gameType = String(game).toLowerCase(); + + // Find or create user for this game + const lookupKey = `${gameType}_player_id`; + let { data: userData } = await supabase + .from("user_profiles") + .select("id, auth_id, email, username") + .eq(lookupKey, String(player_id)) + .single(); + + if (!userData) { + // Create new game player user + const email = `${String(player_id)}@${gameType}.aethex.dev`; + const username = `${gameType}_${String(player_id).substring(0, 8)}`; + + const { data: newUser, error: createError } = await supabase + .from("user_profiles") + .insert({ + [lookupKey]: String(player_id), + username, + user_type: "game_developer", + full_name: String(player_name), + email, + metadata: { + game: gameType, + player_id: String(player_id), + player_name: String(player_name), + platform: platform || null, + }, + }) + .select() + .single(); + + if (createError) { + console.error(`Failed to create ${gameType} user:`, createError); + return res.status(500).json({ error: "Failed to create user" }); + } + + userData = newUser; + } + + // Generate game session token + const sessionToken = require("crypto").randomBytes(32).toString("hex"); + const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000); // 7 days + + // Store game session + const { error: sessionError } = await supabase + .from("game_sessions") + .insert({ + user_id: userData.id, + game: gameType, + session_token: sessionToken, + device_id, + platform, + expires_at: expiresAt.toISOString(), + last_activity: new Date().toISOString(), + }); + + if (sessionError) { + console.error("Failed to create game session:", sessionError); + return res.status(500).json({ error: "Failed to create session" }); + } + + // Return auth data for game + return res.status(200).json({ + success: true, + session_token: sessionToken, + user_id: userData.id, + username: userData.username, + email: userData.email, + game: gameType, + expires_in: 604800, // 7 days in seconds + api_base_url: process.env.VITE_API_BASE || "https://aethex.dev/api", + docs_url: "https://docs.aethex.dev/game-integration", + }); + } catch (error: any) { + console.error("Game authentication error:", error); + return res.status(500).json({ + error: error?.message || "Authentication failed", + }); + } +}