Prettier format pending files

This commit is contained in:
Builder.io 2025-11-09 07:42:14 +00:00
parent 34f8661d1b
commit 7f4dc5c67b
8 changed files with 131 additions and 72 deletions

View file

@ -49,19 +49,22 @@ export default async function handler(req: any, res: any) {
const redirectUri = `${process.env.VITE_API_BASE || "https://aethex.dev"}/api/discord/oauth/callback`; const redirectUri = `${process.env.VITE_API_BASE || "https://aethex.dev"}/api/discord/oauth/callback`;
// Exchange code for access token // Exchange code for access token
const tokenResponse = await fetch("https://discord.com/api/v10/oauth2/token", { const tokenResponse = await fetch(
method: "POST", "https://discord.com/api/v10/oauth2/token",
headers: { {
"Content-Type": "application/x-www-form-urlencoded", method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
client_id: clientId,
client_secret: clientSecret,
grant_type: "authorization_code",
code,
redirect_uri: redirectUri,
}).toString(),
}, },
body: new URLSearchParams({ );
client_id: clientId,
client_secret: clientSecret,
grant_type: "authorization_code",
code,
redirect_uri: redirectUri,
}).toString(),
});
if (!tokenResponse.ok) { if (!tokenResponse.ok) {
const errorData = await tokenResponse.json(); const errorData = await tokenResponse.json();
@ -115,19 +118,23 @@ export default async function handler(req: any, res: any) {
} else { } else {
// Create new user // Create new user
// First create auth user // First create auth user
const { data: authData, error: authError } = await supabase.auth.admin.createUser({ const { data: authData, error: authError } =
email: discordUser.email, await supabase.auth.admin.createUser({
email_confirm: true, email: discordUser.email,
user_metadata: { email_confirm: true,
full_name: discordUser.username, user_metadata: {
avatar_url: discordUser.avatar full_name: discordUser.username,
? `https://cdn.discordapp.com/avatars/${discordUser.id}/${discordUser.avatar}.png` avatar_url: discordUser.avatar
: null, ? `https://cdn.discordapp.com/avatars/${discordUser.id}/${discordUser.avatar}.png`
}, : null,
}); },
});
if (authError || !authData.user) { if (authError || !authData.user) {
console.error("[Discord OAuth] Auth user creation failed:", authError); console.error(
"[Discord OAuth] Auth user creation failed:",
authError,
);
return res.redirect("/login?error=auth_create"); return res.redirect("/login?error=auth_create");
} }
@ -135,17 +142,22 @@ export default async function handler(req: any, res: any) {
isNewUser = true; isNewUser = true;
// Create user profile // Create user profile
const { error: profileError } = await supabase.from("user_profiles").insert({ const { error: profileError } = await supabase
id: userId, .from("user_profiles")
email: discordUser.email, .insert({
full_name: discordUser.username, id: userId,
avatar_url: discordUser.avatar email: discordUser.email,
? `https://cdn.discordapp.com/avatars/${discordUser.id}/${discordUser.avatar}.png` full_name: discordUser.username,
: null, avatar_url: discordUser.avatar
}); ? `https://cdn.discordapp.com/avatars/${discordUser.id}/${discordUser.avatar}.png`
: null,
});
if (profileError) { if (profileError) {
console.error("[Discord OAuth] Profile creation failed:", profileError); console.error(
"[Discord OAuth] Profile creation failed:",
profileError,
);
return res.redirect("/login?error=profile_create"); return res.redirect("/login?error=profile_create");
} }
} }
@ -164,9 +176,10 @@ export default async function handler(req: any, res: any) {
} }
// Generate session token // Generate session token
const { data: sessionData, error: sessionError } = await supabase.auth.admin.createSession({ const { data: sessionData, error: sessionError } =
user_id: userId, await supabase.auth.admin.createSession({
}); user_id: userId,
});
if (sessionError || !sessionData.session) { if (sessionError || !sessionData.session) {
console.error("[Discord OAuth] Session creation failed:", sessionError); console.error("[Discord OAuth] Session creation failed:", sessionError);
@ -174,17 +187,25 @@ export default async function handler(req: any, res: any) {
} }
// Redirect to next page with session // Redirect to next page with session
const nextPath = state && typeof state === "string" && state.startsWith("/") ? state : isNewUser ? "/onboarding" : "/dashboard"; const nextPath =
const redirectUrl = new URL(nextPath, process.env.VITE_API_BASE || "https://aethex.dev"); state && typeof state === "string" && state.startsWith("/")
? state
: isNewUser
? "/onboarding"
: "/dashboard";
const redirectUrl = new URL(
nextPath,
process.env.VITE_API_BASE || "https://aethex.dev",
);
// Set cookies for session (similar to how Supabase does it) // Set cookies for session (similar to how Supabase does it)
res.setHeader( res.setHeader(
"Set-Cookie", "Set-Cookie",
`sb-access-token=${sessionData.session.access_token}; Path=/; HttpOnly; Secure; SameSite=Lax` `sb-access-token=${sessionData.session.access_token}; Path=/; HttpOnly; Secure; SameSite=Lax`,
); );
res.setHeader( res.setHeader(
"Set-Cookie", "Set-Cookie",
`sb-refresh-token=${sessionData.session.refresh_token}; Path=/; HttpOnly; Secure; SameSite=Lax` `sb-refresh-token=${sessionData.session.refresh_token}; Path=/; HttpOnly; Secure; SameSite=Lax`,
); );
res.redirect(redirectUrl.toString()); res.redirect(redirectUrl.toString());

View file

@ -13,10 +13,10 @@ export default function handler(req: any, res: any) {
} }
const redirectUri = `${process.env.VITE_API_BASE || "https://aethex.dev"}/api/discord/oauth/callback`; const redirectUri = `${process.env.VITE_API_BASE || "https://aethex.dev"}/api/discord/oauth/callback`;
// Get the next URL from query params (where to redirect after login) // Get the next URL from query params (where to redirect after login)
const next = req.query.state || "/dashboard"; const next = req.query.state || "/dashboard";
const params = new URLSearchParams({ const params = new URLSearchParams({
client_id: clientId, client_id: clientId,
redirect_uri: redirectUri, redirect_uri: redirectUri,

View file

@ -12,7 +12,9 @@ export default async function handler(req: any, res: any) {
const { verification_code, user_id } = req.body; const { verification_code, user_id } = req.body;
if (!verification_code || !user_id) { if (!verification_code || !user_id) {
return res.status(400).json({ message: "Missing verification code or user ID" }); return res
.status(400)
.json({ message: "Missing verification code or user ID" });
} }
const supabaseUrl = process.env.VITE_SUPABASE_URL; const supabaseUrl = process.env.VITE_SUPABASE_URL;
@ -35,7 +37,8 @@ export default async function handler(req: any, res: any) {
if (verifyError || !verification) { if (verifyError || !verification) {
return res.status(400).json({ return res.status(400).json({
message: "Invalid or expired verification code. Please try /verify again.", message:
"Invalid or expired verification code. Please try /verify again.",
}); });
} }
@ -50,7 +53,8 @@ export default async function handler(req: any, res: any) {
if (existingLink && existingLink.user_id !== user_id) { if (existingLink && existingLink.user_id !== user_id) {
return res.status(400).json({ return res.status(400).json({
message: "This Discord account is already linked to another AeThex account.", message:
"This Discord account is already linked to another AeThex account.",
}); });
} }
@ -63,7 +67,9 @@ export default async function handler(req: any, res: any) {
if (linkError) { if (linkError) {
console.error("[Discord Verify] Link creation failed:", linkError); console.error("[Discord Verify] Link creation failed:", linkError);
return res.status(500).json({ message: "Failed to link Discord account" }); return res
.status(500)
.json({ message: "Failed to link Discord account" });
} }
// Delete used verification code // Delete used verification code

View file

@ -166,7 +166,6 @@ export default function ArmSwitcher() {
onClose={() => setIsModalOpen(false)} onClose={() => setIsModalOpen(false)}
/> />
</div> </div>
</> </>
); );
} }

View file

@ -94,7 +94,8 @@ const ARM_DESCRIPTIONS: Record<string, string> = {
gameforge: gameforge:
"Game Development - Shipping games at the speed of thought with monthly cycles", "Game Development - Shipping games at the speed of thought with monthly cycles",
corp: "Enterprise Solutions - Consulting for large-scale transformations", corp: "Enterprise Solutions - Consulting for large-scale transformations",
foundation: "Community & Education - Building open-source and talent pipelines", foundation:
"Community & Education - Building open-source and talent pipelines",
devlink: devlink:
"Professional Networking - LinkedIn for Roblox developers and creators", "Professional Networking - LinkedIn for Roblox developers and creators",
nexus: "Talent Marketplace - Cross-arm collaboration and opportunities", nexus: "Talent Marketplace - Cross-arm collaboration and opportunities",
@ -128,7 +129,9 @@ export default function ArmSwitcherModal({
onClose(); onClose();
}; };
const selectedArmData = selectedArm ? ARMS.find((a) => a.id === selectedArm) : null; const selectedArmData = selectedArm
? ARMS.find((a) => a.id === selectedArm)
: null;
if (!isOpen) return null; if (!isOpen) return null;
@ -179,7 +182,9 @@ export default function ArmSwitcherModal({
{ARM_DESCRIPTIONS[arm.id]} {ARM_DESCRIPTIONS[arm.id]}
</p> </p>
</div> </div>
<div className={`w-2 h-2 rounded-full mt-1 ${arm.textColor}`} /> <div
className={`w-2 h-2 rounded-full mt-1 ${arm.textColor}`}
/>
</div> </div>
</button> </button>
))} ))}
@ -213,13 +218,17 @@ export default function ArmSwitcherModal({
</div> </div>
{/* Features */} {/* Features */}
<div className={`p-4 rounded-lg ${selectedArmData.bgColor} border border-gray-700`}> <div
className={`p-4 rounded-lg ${selectedArmData.bgColor} border border-gray-700`}
>
<h3 className="text-sm font-semibold text-gray-200 mb-3"> <h3 className="text-sm font-semibold text-gray-200 mb-3">
What you'll get: What you'll get:
</h3> </h3>
<ul className="space-y-2"> <ul className="space-y-2">
<li className="flex items-start gap-2"> <li className="flex items-start gap-2">
<span className={`text-lg mt-0.5 ${selectedArmData.textColor}`}> <span
className={`text-lg mt-0.5 ${selectedArmData.textColor}`}
>
</span> </span>
<span className="text-sm text-gray-300"> <span className="text-sm text-gray-300">
@ -227,7 +236,9 @@ export default function ArmSwitcherModal({
</span> </span>
</li> </li>
<li className="flex items-start gap-2"> <li className="flex items-start gap-2">
<span className={`text-lg mt-0.5 ${selectedArmData.textColor}`}> <span
className={`text-lg mt-0.5 ${selectedArmData.textColor}`}
>
🚀 🚀
</span> </span>
<span className="text-sm text-gray-300"> <span className="text-sm text-gray-300">
@ -235,7 +246,9 @@ export default function ArmSwitcherModal({
</span> </span>
</li> </li>
<li className="flex items-start gap-2"> <li className="flex items-start gap-2">
<span className={`text-lg mt-0.5 ${selectedArmData.textColor}`}> <span
className={`text-lg mt-0.5 ${selectedArmData.textColor}`}
>
🎯 🎯
</span> </span>
<span className="text-sm text-gray-300"> <span className="text-sm text-gray-300">

View file

@ -1,5 +1,10 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { AlertCircle, CheckCircle, AlertTriangle, RefreshCw } from "lucide-react"; import {
AlertCircle,
CheckCircle,
AlertTriangle,
RefreshCw,
} from "lucide-react";
interface DiagnosticData { interface DiagnosticData {
timestamp: string; timestamp: string;
@ -46,7 +51,7 @@ export default function AdminDiscordDiagnostic() {
setDiagnostic(data); setDiagnostic(data);
} catch (err) { } catch (err) {
setError( setError(
err instanceof Error ? err.message : "Failed to fetch diagnostic" err instanceof Error ? err.message : "Failed to fetch diagnostic",
); );
} finally { } finally {
setLoading(false); setLoading(false);
@ -60,7 +65,9 @@ export default function AdminDiscordDiagnostic() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<h3 className="text-lg font-bold text-white">Discord Configuration Diagnostic</h3> <h3 className="text-lg font-bold text-white">
Discord Configuration Diagnostic
</h3>
<button <button
onClick={fetchDiagnostic} onClick={fetchDiagnostic}
disabled={loading} disabled={loading}

View file

@ -77,7 +77,9 @@ export default function DiscordVerify() {
}, 3000); }, 3000);
} catch (err) { } catch (err) {
setError( setError(
err instanceof Error ? err.message : "An error occurred. Please try again." err instanceof Error
? err.message
: "An error occurred. Please try again.",
); );
setIsLoading(false); setIsLoading(false);
} }
@ -129,7 +131,8 @@ export default function DiscordVerify() {
Discord User Discord User
</p> </p>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
{discordUser.username}#{discordUser.discriminator || "0000"} {discordUser.username}#
{discordUser.discriminator || "0000"}
</p> </p>
</div> </div>
@ -153,8 +156,15 @@ export default function DiscordVerify() {
</p> </p>
<ol className="text-sm text-muted-foreground space-y-1 list-decimal list-inside"> <ol className="text-sm text-muted-foreground space-y-1 list-decimal list-inside">
<li>Open Discord</li> <li>Open Discord</li>
<li>Go to any server where the AeThex bot is installed</li> <li>
<li>Type <code className="bg-background/50 px-2 py-1 rounded">/verify</code></li> Go to any server where the AeThex bot is installed
</li>
<li>
Type{" "}
<code className="bg-background/50 px-2 py-1 rounded">
/verify
</code>
</li>
<li>Copy the 6-digit code from the bot's response</li> <li>Copy the 6-digit code from the bot's response</li>
</ol> </ol>
</div> </div>
@ -213,8 +223,8 @@ export default function DiscordVerify() {
{/* Info Box */} {/* Info Box */}
<div className="mt-6 p-4 rounded-lg bg-secondary/20 border border-border/50"> <div className="mt-6 p-4 rounded-lg bg-secondary/20 border border-border/50">
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
💡 <strong>Tip:</strong> You can also sign in directly with Discord 💡 <strong>Tip:</strong> You can also sign in directly with
on the login page if you're creating a new account. Discord on the login page if you're creating a new account.
</p> </p>
</div> </div>
</div> </div>

View file

@ -1500,21 +1500,21 @@ export function createServer() {
// Add recommendations based on validation // Add recommendations based on validation
if (!botToken) { if (!botToken) {
diagnostics.recommendations.push( diagnostics.recommendations.push(
"❌ DISCORD_BOT_TOKEN not set. Set it in environment variables." "❌ DISCORD_BOT_TOKEN not set. Set it in environment variables.",
); );
} else if ((botToken?.length || 0) < 20) { } else if ((botToken?.length || 0) < 20) {
diagnostics.recommendations.push( diagnostics.recommendations.push(
`❌ DISCORD_BOT_TOKEN appears invalid (length: ${botToken?.length}). Should be 60+ characters.` `❌ DISCORD_BOT_TOKEN appears invalid (length: ${botToken?.length}). Should be 60+ characters.`,
); );
} else { } else {
diagnostics.recommendations.push( diagnostics.recommendations.push(
"✅ DISCORD_BOT_TOKEN format looks valid" "✅ DISCORD_BOT_TOKEN format looks valid",
); );
} }
if (!clientId) { if (!clientId) {
diagnostics.recommendations.push( diagnostics.recommendations.push(
"❌ DISCORD_CLIENT_ID not set. Set it to your application's ID." "❌ DISCORD_CLIENT_ID not set. Set it to your application's ID.",
); );
} else { } else {
diagnostics.recommendations.push("✅ DISCORD_CLIENT_ID is set"); diagnostics.recommendations.push("✅ DISCORD_CLIENT_ID is set");
@ -1522,7 +1522,7 @@ export function createServer() {
if (!publicKey) { if (!publicKey) {
diagnostics.recommendations.push( diagnostics.recommendations.push(
"❌ DISCORD_PUBLIC_KEY not set. Needed for signature verification." "❌ DISCORD_PUBLIC_KEY not set. Needed for signature verification.",
); );
} else { } else {
diagnostics.recommendations.push("✅ DISCORD_PUBLIC_KEY is set"); diagnostics.recommendations.push("✅ DISCORD_PUBLIC_KEY is set");
@ -1537,22 +1537,25 @@ export function createServer() {
headers: { headers: {
Authorization: `Bot ${botToken}`, Authorization: `Bot ${botToken}`,
}, },
} },
); );
diagnostics.testRequest = { diagnostics.testRequest = {
...diagnostics.testRequest, ...diagnostics.testRequest,
status: testResponse.status === 200 ? "✅ Success" : `❌ Failed (${testResponse.status})`, status:
testResponse.status === 200
? "✅ Success"
: `❌ Failed (${testResponse.status})`,
responseCode: testResponse.status, responseCode: testResponse.status,
}; };
if (testResponse.status === 401) { if (testResponse.status === 401) {
diagnostics.recommendations.push( diagnostics.recommendations.push(
"❌ Token authentication failed (401). The token may be invalid or revoked." "❌ Token authentication failed (401). The token may be invalid or revoked.",
); );
} else if (testResponse.status === 200) { } else if (testResponse.status === 200) {
diagnostics.recommendations.push( diagnostics.recommendations.push(
"✅ Token authentication successful with Discord API!" "✅ Token authentication successful with Discord API!",
); );
} }
} catch (error) { } catch (error) {