diff --git a/api/discord/activity-auth.ts b/api/discord/activity-auth.ts
index 1e85a6df..73749faa 100644
--- a/api/discord/activity-auth.ts
+++ b/api/discord/activity-auth.ts
@@ -3,7 +3,7 @@ import { createClient } from "@supabase/supabase-js";
const supabase = createClient(
process.env.SUPABASE_URL || "",
- process.env.SUPABASE_SERVICE_ROLE || ""
+ process.env.SUPABASE_SERVICE_ROLE || "",
);
interface ActivityAuthRequest {
@@ -21,10 +21,7 @@ interface UserData {
primary_arm: string | null;
}
-export default async function handler(
- req: VercelRequest,
- res: VercelResponse
-) {
+export default async function handler(req: VercelRequest, res: VercelResponse) {
if (req.method !== "POST") {
res.setHeader("Allow", "POST");
return res.status(405).json({ error: "Method not allowed" });
@@ -38,15 +35,20 @@ export default async function handler(
}
// Verify the access token with Discord API
- const discordResponse = await fetch("https://discord.com/api/v10/users/@me", {
- headers: {
- Authorization: `Bearer ${access_token}`,
+ const discordResponse = await fetch(
+ "https://discord.com/api/v10/users/@me",
+ {
+ headers: {
+ Authorization: `Bearer ${access_token}`,
+ },
},
- });
+ );
if (!discordResponse.ok) {
if (discordResponse.status === 401) {
- return res.status(401).json({ error: "Invalid or expired access token" });
+ return res
+ .status(401)
+ .json({ error: "Invalid or expired access token" });
}
throw new Error(`Discord API error: ${discordResponse.statusText}`);
}
diff --git a/api/discord/admin-register-commands.ts b/api/discord/admin-register-commands.ts
index c6ed17c1..842bfb84 100644
--- a/api/discord/admin-register-commands.ts
+++ b/api/discord/admin-register-commands.ts
@@ -46,10 +46,7 @@ const COMMANDS: CommandData[] = [
},
];
-export default async function handler(
- req: VercelRequest,
- res: VercelResponse
-) {
+export default async function handler(req: VercelRequest, res: VercelResponse) {
// Verify this is a POST request
if (req.method !== "POST") {
res.setHeader("Allow", "POST");
@@ -77,18 +74,16 @@ export default async function handler(
try {
const rest = new REST({ version: "10" }).setToken(
- process.env.DISCORD_BOT_TOKEN!
+ process.env.DISCORD_BOT_TOKEN!,
);
- console.log(
- `š Registering ${COMMANDS.length} Discord slash commands...`
- );
+ console.log(`š Registering ${COMMANDS.length} Discord slash commands...`);
try {
// Try bulk update first
const data = await rest.put(
Routes.applicationCommands(process.env.DISCORD_CLIENT_ID!),
- { body: COMMANDS }
+ { body: COMMANDS },
);
console.log(`ā
Successfully registered ${data.length} slash commands`);
@@ -102,7 +97,7 @@ export default async function handler(
// Handle Error 50240 (Entry Point conflict)
if (bulkError.code === 50240) {
console.warn(
- "ā ļø Error 50240: Entry Point detected. Registering individually..."
+ "ā ļø Error 50240: Entry Point detected. Registering individually...",
);
const results = [];
@@ -114,7 +109,7 @@ export default async function handler(
// Try to post individual command
const posted = await rest.post(
Routes.applicationCommands(process.env.DISCORD_CLIENT_ID!),
- { body: command }
+ { body: command },
);
results.push({
name: command.name,
@@ -141,7 +136,7 @@ export default async function handler(
}
console.log(
- `ā
Registration complete: ${successCount} new, ${skipCount} already existed`
+ `ā
Registration complete: ${successCount} new, ${skipCount} already existed`,
);
return res.status(200).json({
diff --git a/client/App.tsx b/client/App.tsx
index 97df9233..e95e30bd 100644
--- a/client/App.tsx
+++ b/client/App.tsx
@@ -122,247 +122,265 @@ const App = () => (
-
-
-
-
-
-
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- }
- />
- } />
- } />
- }
- />
-
- } />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
-
- }
- />
- } />
- }
- />
- } />
- } />
- } />
- } />
- } />
- } />
-
- {/* Creator Network routes */}
- } />
- }
- />
- } />
- }
- />
-
- {/* Service routes */}
- }
- />
- }
- />
- } />
- } />
- }
- />
- } />
-
- {/* New Arm Landing Pages */}
- } />
- }
- />
- } />
- }
- />
-
- } />
- }
- />
- }
- />
- }
- />
-
- } />
- }
- />
- }
- />
- } />
-
- } />
- }
- />
- }
- />
- }
- />
-
- {/* Dev-Link routes */}
- } />
- }
- />
-
- {/* Nexus routes */}
- } />
-
- {/* Resource routes */}
- }>
- } />
- } />
- } />
+
+
+
+
+
+
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
}
+ path="/projects/:projectId/board"
+ element={}
+ />
+ } />
+ } />
+ }
/>
- } />
- } />
- } />
- } />
- } />
-
- } />
- } />
- } />
- } />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- } />
- } />
- } />
- } />
- } />
- {/* Informational routes */}
- } />
- }
- />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
- {/* Legal routes */}
- } />
- } />
+ }
+ />
+ } />
+ }
+ />
+ } />
+ } />
+ } />
+ }
+ />
+ } />
+ } />
- {/* Discord routes */}
- } />
- } />
- }
- />
+ {/* Creator Network routes */}
+ } />
+ }
+ />
+ }
+ />
+ }
+ />
- {/* Explicit 404 route for static hosting fallbacks */}
- } />
- {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
- } />
-
-
-
+ {/* Service routes */}
+ }
+ />
+ }
+ />
+ }
+ />
+ } />
+ }
+ />
+ } />
+
+ {/* New Arm Landing Pages */}
+ } />
+ }
+ />
+ } />
+ }
+ />
+
+ } />
+ }
+ />
+ }
+ />
+ }
+ />
+
+ } />
+ }
+ />
+ }
+ />
+ }
+ />
+
+ } />
+ }
+ />
+ }
+ />
+ }
+ />
+
+ {/* Dev-Link routes */}
+ } />
+ }
+ />
+
+ {/* Nexus routes */}
+ } />
+
+ {/* Resource routes */}
+ }>
+ } />
+ } />
+ } />
+ }
+ />
+ } />
+ } />
+ } />
+ } />
+ }
+ />
+
+ } />
+ } />
+ } />
+ } />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ } />
+ } />
+ } />
+ } />
+ } />
+
+ {/* Informational routes */}
+ } />
+ }
+ />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
+ {/* Legal routes */}
+ } />
+ } />
+
+ {/* Discord routes */}
+ } />
+ } />
+ }
+ />
+
+ {/* Explicit 404 route for static hosting fallbacks */}
+ } />
+ {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
+ } />
+
+
+
diff --git a/client/components/admin/AdminDiscordManagement.tsx b/client/components/admin/AdminDiscordManagement.tsx
index b29e5080..363232e7 100644
--- a/client/components/admin/AdminDiscordManagement.tsx
+++ b/client/components/admin/AdminDiscordManagement.tsx
@@ -127,7 +127,7 @@ export function AdminDiscordManagement() {
setRegisterSuccess(null);
const adminToken = prompt(
- "Enter admin registration token (from environment variables):"
+ "Enter admin registration token (from environment variables):",
);
if (!adminToken) {
setRegisterError("Registration cancelled");
@@ -149,7 +149,7 @@ export function AdminDiscordManagement() {
const data = await response.json();
setRegisterSuccess(
- data.message || "Discord commands registered successfully!"
+ data.message || "Discord commands registered successfully!",
);
setTimeout(() => setRegisterSuccess(null), 5000);
} catch (err) {
diff --git a/client/contexts/DiscordActivityContext.tsx b/client/contexts/DiscordActivityContext.tsx
index 575c7808..06920623 100644
--- a/client/contexts/DiscordActivityContext.tsx
+++ b/client/contexts/DiscordActivityContext.tsx
@@ -31,7 +31,7 @@ export const useDiscordActivity = () => {
const context = useContext(DiscordActivityContext);
if (!context) {
throw new Error(
- "useDiscordActivity must be used within DiscordActivityProvider"
+ "useDiscordActivity must be used within DiscordActivityProvider",
);
}
return context;
@@ -41,9 +41,9 @@ interface DiscordActivityProviderProps {
children: React.ReactNode;
}
-export const DiscordActivityProvider: React.FC = ({
- children,
-}) => {
+export const DiscordActivityProvider: React.FC<
+ DiscordActivityProviderProps
+> = ({ children }) => {
const [isActivity, setIsActivity] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [user, setUser] = useState(null);
@@ -64,11 +64,10 @@ export const DiscordActivityProvider: React.FC = (
setIsLoading(true);
// Import the Discord SDK dynamically
- const { DiscordSDK } = await import(
- "@discord/embedded-app-sdk"
- );
+ const { DiscordSDK } = await import("@discord/embedded-app-sdk");
- const clientId = import.meta.env.VITE_DISCORD_CLIENT_ID || "578971245454950421";
+ const clientId =
+ import.meta.env.VITE_DISCORD_CLIENT_ID || "578971245454950421";
const sdk = new DiscordSDK({
clientId,
@@ -119,7 +118,7 @@ export const DiscordActivityProvider: React.FC = (
"Content-Type": "application/json",
},
body: JSON.stringify({
- access_token: currentUser.access_token || ""
+ access_token: currentUser.access_token || "",
}),
});
diff --git a/client/pages/Activity.tsx b/client/pages/Activity.tsx
index 1163522f..14cf00c0 100644
--- a/client/pages/Activity.tsx
+++ b/client/pages/Activity.tsx
@@ -132,7 +132,9 @@ export default function Activity() {
/profile,{" "}
/set-realm,
and{" "}
- /verify-role{" "}
+
+ /verify-role
+ {" "}
to manage your account within Discord.
diff --git a/discord-bot/bot.js b/discord-bot/bot.js
index 67a14f69..d9742d97 100644
--- a/discord-bot/bot.js
+++ b/discord-bot/bot.js
@@ -114,9 +114,7 @@ client.login(process.env.DISCORD_BOT_TOKEN);
client.once("ready", () => {
console.log(`ā
Bot logged in as ${client.user.tag}`);
console.log(`š” Listening in ${client.guilds.cache.size} server(s)`);
- console.log(
- "ā¹ļø Commands are registered via: npm run register-commands"
- );
+ console.log("ā¹ļø Commands are registered via: npm run register-commands");
// Set bot status
client.user.setActivity("/verify to link your AeThex account", {
diff --git a/discord-bot/scripts/register-commands.js b/discord-bot/scripts/register-commands.js
index 9d92dc21..27ffb8d9 100644
--- a/discord-bot/scripts/register-commands.js
+++ b/discord-bot/scripts/register-commands.js
@@ -4,16 +4,13 @@ const path = require("path");
require("dotenv").config();
// Validate environment variables
-const requiredEnvVars = [
- "DISCORD_BOT_TOKEN",
- "DISCORD_CLIENT_ID",
-];
+const requiredEnvVars = ["DISCORD_BOT_TOKEN", "DISCORD_CLIENT_ID"];
const missingVars = requiredEnvVars.filter((envVar) => !process.env[envVar]);
if (missingVars.length > 0) {
console.error(
"ā FATAL ERROR: Missing required environment variables:",
- missingVars.join(", ")
+ missingVars.join(", "),
);
console.error("\nPlease set these before running command registration:");
missingVars.forEach((envVar) => {
@@ -43,55 +40,68 @@ for (const file of commandFiles) {
async function registerCommands() {
try {
const rest = new REST({ version: "10" }).setToken(
- process.env.DISCORD_BOT_TOKEN
+ process.env.DISCORD_BOT_TOKEN,
);
console.log(`\nš Registering ${commands.length} slash commands...`);
- console.log("ā ļø This will co-exist with Discord's auto-generated Entry Point command.\n");
+ console.log(
+ "ā ļø This will co-exist with Discord's auto-generated Entry Point command.\n",
+ );
try {
const data = await rest.put(
Routes.applicationCommands(process.env.DISCORD_CLIENT_ID),
- { body: commands }
+ { body: commands },
);
console.log(`ā
Successfully registered ${data.length} slash commands.`);
console.log("\nš Command registration complete!");
console.log("ā¹ļø Your commands are now live in Discord.");
- console.log("ā¹ļø The Entry Point command (for Activities) will be managed by Discord.\n");
+ console.log(
+ "ā¹ļø The Entry Point command (for Activities) will be managed by Discord.\n",
+ );
} catch (error) {
// Handle Entry Point command conflict
if (error.code === 50240) {
console.warn(
- "ā ļø Error 50240: Entry Point command detected (Discord Activity enabled)."
+ "ā ļø Error 50240: Entry Point command detected (Discord Activity enabled).",
);
console.warn("Registering commands individually...\n");
-
+
let successCount = 0;
for (const command of commands) {
try {
await rest.post(
Routes.applicationCommands(process.env.DISCORD_CLIENT_ID),
- { body: command }
+ { body: command },
);
successCount++;
} catch (postError) {
if (postError.code === 50045) {
- console.warn(` ā ļø ${command.name}: Already registered (skipping)`);
+ console.warn(
+ ` ā ļø ${command.name}: Already registered (skipping)`,
+ );
} else {
console.error(` ā ${command.name}: ${postError.message}`);
}
}
}
-
- console.log(`\nā
Registered ${successCount} slash commands (individual mode).`);
+
+ console.log(
+ `\nā
Registered ${successCount} slash commands (individual mode).`,
+ );
console.log("š Command registration complete!");
- console.log("ā¹ļø The Entry Point command will be managed by Discord.\n");
+ console.log(
+ "ā¹ļø The Entry Point command will be managed by Discord.\n",
+ );
} else {
throw error;
}
}
} catch (error) {
- console.error("ā Fatal error registering commands:", error.message || error);
+ console.error(
+ "ā Fatal error registering commands:",
+ error.message || error,
+ );
process.exit(1);
}
}
diff --git a/docs/DISCORD-ACTIVITY-DEPLOYMENT.md b/docs/DISCORD-ACTIVITY-DEPLOYMENT.md
index 8723f6ed..4e1eeda8 100644
--- a/docs/DISCORD-ACTIVITY-DEPLOYMENT.md
+++ b/docs/DISCORD-ACTIVITY-DEPLOYMENT.md
@@ -11,11 +11,13 @@ If you can't run `npm` in your development environment, follow this guide to dep
Add these to your deployment platform (Vercel, PebbleHost):
### Vercel (Frontend)
+
```
VITE_DISCORD_CLIENT_ID=578971245454950421
```
### PebbleHost (Discord Bot)
+
```
DISCORD_BOT_TOKEN=
DISCORD_CLIENT_ID=578971245454950421
@@ -26,6 +28,7 @@ BOT_PORT=3000
```
### Vercel (Backend - for command registration)
+
```
DISCORD_BOT_TOKEN=
DISCORD_CLIENT_ID=578971245454950421
@@ -68,15 +71,15 @@ You can add a button to `/admin` panel that triggers this endpoint:
```typescript
async function registerCommands() {
- const response = await fetch('/api/discord/admin-register-commands', {
- method: 'POST',
+ const response = await fetch("/api/discord/admin-register-commands", {
+ method: "POST",
headers: {
- 'Authorization': `Bearer ${process.env.DISCORD_ADMIN_REGISTER_TOKEN}`,
- 'Content-Type': 'application/json',
+ Authorization: `Bearer ${process.env.DISCORD_ADMIN_REGISTER_TOKEN}`,
+ "Content-Type": "application/json",
},
});
const data = await response.json();
- console.log('Registration result:', data);
+ console.log("Registration result:", data);
}
```
@@ -131,10 +134,12 @@ Command registration happens via the API endpoint (Step 3), not on bot startup.
### Error 50240: "Cannot remove Entry Point command"
**This happens if:**
+
- You enable Activities, then the bot tries to register commands via bulk update
- The bot is trying to overwrite the auto-generated Entry Point command
**Solution:**
+
- ā
Your bot code has been fixed (bot no longer registers on startup)
- Just call the `/api/discord/admin-register-commands` endpoint (Step 3)
- The endpoint handles Error 50240 gracefully
@@ -142,6 +147,7 @@ Command registration happens via the API endpoint (Step 3), not on bot startup.
### Activity not loading in Discord
**Check:**
+
1. Activities enabled in Discord Developer Portal ā
2. Activity URL is set to `https://aethex.dev/activity` (not an IP) ā
3. Frontend is deployed to Vercel ā
@@ -151,6 +157,7 @@ Command registration happens via the API endpoint (Step 3), not on bot startup.
### "Unauthorized" error when calling register endpoint
**Check:**
+
1. `DISCORD_ADMIN_REGISTER_TOKEN` is set in Vercel environment variables
2. You're passing the correct token in the `Authorization: Bearer` header
3. The token matches exactly (no extra spaces)
@@ -158,6 +165,7 @@ Command registration happens via the API endpoint (Step 3), not on bot startup.
### Bot not responding to commands
**Check:**
+
1. Bot is online on PebbleHost (check logs)
2. Commands are registered (call `/api/discord/admin-register-commands` and check response)
3. Response shows commands registered successfully
@@ -167,13 +175,13 @@ Command registration happens via the API endpoint (Step 3), not on bot startup.
## Quick Reference
-| What | How |
-|------|-----|
-| Enable Activities | Discord Developer Portal ā Settings ā Activities ā Enable |
+| What | How |
+| ----------------- | -------------------------------------------------------------- |
+| Enable Activities | Discord Developer Portal ā Settings ā Activities ā Enable |
| Register Commands | POST to `/api/discord/admin-register-commands` with auth token |
-| Deploy Bot | Push to PebbleHost, bot starts with `npm start` |
-| Deploy Frontend | Push to GitHub, Vercel auto-deploys |
-| Test Activity | Open Discord, click Activity button, should load |
+| Deploy Bot | Push to PebbleHost, bot starts with `npm start` |
+| Deploy Frontend | Push to GitHub, Vercel auto-deploys |
+| Test Activity | Open Discord, click Activity button, should load |
---
@@ -209,6 +217,6 @@ Plus the auto-generated **Entry Point** command (managed by Discord for Activiti
ā
Everything can be deployed via web interfaces
ā
Commands registered via API endpoint
ā
Error 50240 handled automatically
-ā
Activity loads instantly in Discord
+ā
Activity loads instantly in Discord
**You're all set!** š
diff --git a/docs/DISCORD-ADMIN-COMMANDS-REGISTRATION.md b/docs/DISCORD-ADMIN-COMMANDS-REGISTRATION.md
index 26a2f88a..3c21da0a 100644
--- a/docs/DISCORD-ADMIN-COMMANDS-REGISTRATION.md
+++ b/docs/DISCORD-ADMIN-COMMANDS-REGISTRATION.md
@@ -24,10 +24,12 @@ Click this button.
A popup will appear asking for your **admin registration token**.
This token is:
+
- Set in your Vercel environment variables as `DISCORD_ADMIN_REGISTER_TOKEN`
- A random secure string (e.g., `sk-admin-aethex-discord-2024`)
**Example popup:**
+
```
Enter admin registration token (from environment variables):
[_________________________] [OK] [Cancel]
@@ -40,16 +42,19 @@ The button will show **"Registering..."** with a spinning loader.
Once complete, you'll see one of:
**ā
Success:**
+
```
ā
Registered 5 new commands (Entry Point already exists)
```
**ā ļø Partial Success (Error 50240):**
+
```
ā
Registered 5 new commands (Entry Point managed by Discord)
```
**ā Error:**
+
```
ā Invalid or expired access token
```
@@ -77,6 +82,7 @@ Plus Discord's auto-generated **"Entry Point"** command (for Discord Activities)
**Issue:** Getting this error when registering.
**Solution:**
+
1. Check your `DISCORD_ADMIN_REGISTER_TOKEN` environment variable in Vercel
2. Make sure you entered the token exactly as it's set (case-sensitive)
3. Verify token doesn't have extra spaces
@@ -86,6 +92,7 @@ Plus Discord's auto-generated **"Entry Point"** command (for Discord Activities)
**Issue:** Generic error when clicking the button.
**Check:**
+
1. Is your bot deployed on PebbleHost?
2. Are your `DISCORD_BOT_TOKEN` and `DISCORD_CLIENT_ID` env vars set on Vercel (backend)?
3. Open browser console (F12) ā Network tab ā Check the POST request to `/api/discord/admin-register-commands`
@@ -93,6 +100,7 @@ Plus Discord's auto-generated **"Entry Point"** command (for Discord Activities)
### "Entry Point command already exists" (Not an Error)
**This is expected!** When you enable Discord Activities:
+
1. Discord auto-creates an "Entry Point" command
2. Our script recognizes this and doesn't try to overwrite it
3. Your bot's 5 commands live alongside it peacefully
@@ -102,6 +110,7 @@ Plus Discord's auto-generated **"Entry Point"** command (for Discord Activities)
## Environment Variables Required
**On Vercel (Backend):**
+
```
DISCORD_BOT_TOKEN=
DISCORD_CLIENT_ID=578971245454950421
@@ -109,6 +118,7 @@ DISCORD_ADMIN_REGISTER_TOKEN=sk-admin-aethex-discord-2024
```
**On PebbleHost (Bot):**
+
```
DISCORD_BOT_TOKEN=
DISCORD_CLIENT_ID=578971245454950421
@@ -124,6 +134,7 @@ SUPABASE_SERVICE_ROLE=
If the admin button doesn't work, you can also register commands using:
### curl (if you have PebbleHost console access)
+
```bash
curl -X POST https://aethex.dev/api/discord/admin-register-commands \
-H "Authorization: Bearer YOUR_DISCORD_ADMIN_REGISTER_TOKEN" \
@@ -131,6 +142,7 @@ curl -X POST https://aethex.dev/api/discord/admin-register-commands \
```
### Postman
+
1. Create POST request to `https://aethex.dev/api/discord/admin-register-commands`
2. Add header: `Authorization: Bearer YOUR_DISCORD_ADMIN_REGISTER_TOKEN`
3. Click Send
@@ -142,6 +154,6 @@ curl -X POST https://aethex.dev/api/discord/admin-register-commands \
ā
Click "Register Commands" in Admin ā Discord tab
ā
Enter your admin token
ā
Wait for success confirmation
-ā
Commands are now live in Discord
+ā
Commands are now live in Discord
Done! š