import { redirect } from "@remix-run/node"; import type { LoaderFunctionArgs } from "@remix-run/node"; import { githubApp } from "~/lib/github-app.server"; import { getSession, commitSession } from "~/lib/session.server"; import { accountLinkingService } from "~/lib/account-linking.server"; export async function loader({ request }: LoaderFunctionArgs) { const url = new URL(request.url); const code = url.searchParams.get("code"); const state = url.searchParams.get("state"); const error = url.searchParams.get("error"); const installation_id = url.searchParams.get("installation_id"); const setup_action = url.searchParams.get("setup_action"); console.log('🔄 GitHub OAuth callback received'); if (error) { console.log('- Error:', error); } if (installation_id) { console.log('- Installation ID:', installation_id); } // Handle OAuth errors if (error) { console.error("GitHub OAuth error:", error); return redirect(`/?error=oauth_failed&details=${encodeURIComponent(error)}`); } if (!code) { console.error("No authorization code received"); return redirect("/?error=no_code"); } try { // Exchange code for access token and get user info const userAuth = await githubApp.handleCallback(code, state || undefined); console.log('✅ GitHub OAuth successful for user:', userAuth.login); // Get existing session const session = await getSession(request.headers.get("Cookie")); let userSession = session.get('user') || { isLinked: false }; // Add GitHub info to session userSession.github = { userId: userAuth.id.toString(), login: userAuth.login, name: userAuth.name, email: userAuth.email, avatar_url: userAuth.avatar_url, }; // Check if we can link accounts (if HuggingFace auth exists) if (userSession.huggingface) { const linkCheck = accountLinkingService.canLink( userAuth.id.toString(), userSession.huggingface.username ); if (linkCheck.canLink) { // Create account link const accountLink = accountLinkingService.createLink( userAuth.id.toString(), userAuth.login, userSession.huggingface.username ); userSession.isLinked = true; userSession.linkedAt = accountLink.linkedAt; console.log(`🔗 Accounts automatically linked: ${userAuth.login} ↔ ${userSession.huggingface.username}`); } else { console.warn('âš ī¸ Cannot link accounts:', linkCheck.reason); userSession.isLinked = false; } } else { console.log('â„šī¸ No HuggingFace authentication found, GitHub auth saved for later linking'); userSession.isLinked = false; } // Save updated session session.set('user', userSession); const redirectUrl = installation_id ? "/install" : "/"; return redirect(redirectUrl, { headers: { "Set-Cookie": await commitSession(session), }, }); } catch (error: any) { console.error("GitHub callback error:", error); // Provide more specific error information let errorCode = "callback_failed"; if (error.message?.includes("bad_verification_code") || error.message?.includes("incorrect or expired")) { errorCode = "expired_code"; } else if (error.message?.includes("client_id")) { errorCode = "invalid_client"; } return redirect(`/?error=${errorCode}&message=${encodeURIComponent(error.message)}`); } }