diff --git a/.replit b/.replit
index 9585c0f..696ae75 100644
--- a/.replit
+++ b/.replit
@@ -21,6 +21,10 @@ externalPort = 80
localPort = 8080
externalPort = 8080
+[[ports]]
+localPort = 45655
+externalPort = 3000
+
[workflows]
runButton = "Project"
diff --git a/aethex-bot/bot.js b/aethex-bot/bot.js
index 7ecb390..5f226de 100644
--- a/aethex-bot/bot.js
+++ b/aethex-bot/bot.js
@@ -718,7 +718,7 @@ if (fs.existsSync(sentinelPath)) {
// =============================================================================
const listenersPath = path.join(__dirname, "listeners");
-const generalListenerFiles = ['welcome.js', 'goodbye.js', 'xpTracker.js', 'reactionXp.js', 'voiceXp.js', 'starboard.js'];
+const generalListenerFiles = ['welcome.js', 'goodbye.js', 'xpTracker.js', 'reactionXp.js', 'voiceXp.js', 'starboard.js', 'federationProtection.js'];
for (const file of generalListenerFiles) {
const filePath = path.join(listenersPath, file);
if (fs.existsSync(filePath)) {
@@ -2500,33 +2500,22 @@ client.login(token).catch((error) => {
});
// =============================================================================
-// DYNAMIC STATUS ROTATION
+// BOT STATUS - WATCHING PROTECTING THE FEDERATION
// =============================================================================
-function startDynamicStatus(client) {
- const statuses = [
- () => ({ name: `${client.guilds.cache.size} servers`, type: 3 }), // Watching
- () => ({ name: `${client.guilds.cache.reduce((sum, g) => sum + g.memberCount, 0).toLocaleString()} members`, type: 3 }), // Watching
- () => ({ name: '/help | aethex.studio', type: 0 }), // Playing
- () => ({ name: '🛡️ Guarding the Federation', type: 4 }), // Custom
- () => ({ name: 'for threats', type: 3 }), // Watching
- () => ({ name: '⚔️ Warden • Free Forever', type: 4 }), // Custom
- ];
-
- let currentIndex = 0;
-
- const updateStatus = () => {
- try {
- const status = statuses[currentIndex]();
- client.user.setActivity(status.name, { type: status.type });
- currentIndex = (currentIndex + 1) % statuses.length;
- } catch (e) {
- console.error('[Status] Error updating status:', e.message);
- }
- };
-
- updateStatus();
- setInterval(updateStatus, 30000); // Rotate every 30 seconds
+function setWardenStatus(client) {
+ try {
+ client.user.setPresence({
+ activities: [{
+ name: 'Protecting the Federation',
+ type: 3 // ActivityType.Watching
+ }],
+ status: 'online'
+ });
+ console.log('[Status] Set to: WATCHING Protecting the Federation');
+ } catch (e) {
+ console.error('[Status] Error setting status:', e.message);
+ }
}
client.once("clientReady", async () => {
@@ -2550,8 +2539,8 @@ client.once("clientReady", async () => {
console.error("Failed to register commands:", regResult.error);
}
- // Dynamic rotating status
- startDynamicStatus(client);
+ // Static status: WATCHING Protecting the Federation
+ setWardenStatus(client);
if (setupFeedListener && supabase) {
setupFeedListener(client);
diff --git a/aethex-bot/commands/federation.js b/aethex-bot/commands/federation.js
index 678aa32..504c077 100644
--- a/aethex-bot/commands/federation.js
+++ b/aethex-bot/commands/federation.js
@@ -1,132 +1,696 @@
-const { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits } = require('discord.js');
+const { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js');
const { getServerMode, EMBED_COLORS } = require('../utils/modeHelper');
module.exports = {
data: new SlashCommandBuilder()
.setName('federation')
- .setDescription('Manage cross-server role synchronization')
- .setDefaultMemberPermissions(PermissionFlagsBits.ManageRoles)
- .addSubcommand(subcommand =>
- subcommand
- .setName('link')
- .setDescription('Link a role for cross-server sync')
- .addRoleOption(option =>
- option.setName('role')
- .setDescription('Role to sync across servers')
- .setRequired(true)
- )
+ .setDescription('AeThex Federation - Global protection & cross-server network')
+ .addSubcommandGroup(group =>
+ group
+ .setName('roles')
+ .setDescription('Manage cross-server role synchronization')
+ .addSubcommand(sub => sub.setName('link').setDescription('Link a role for cross-server sync')
+ .addRoleOption(opt => opt.setName('role').setDescription('Role to sync').setRequired(true)))
+ .addSubcommand(sub => sub.setName('unlink').setDescription('Remove a role from sync')
+ .addRoleOption(opt => opt.setName('role').setDescription('Role to remove').setRequired(true)))
+ .addSubcommand(sub => sub.setName('list').setDescription('List all linked roles'))
)
- .addSubcommand(subcommand =>
- subcommand
- .setName('unlink')
- .setDescription('Remove a role from sync')
- .addRoleOption(option =>
- option.setName('role')
- .setDescription('Role to remove from sync')
- .setRequired(true)
- )
+ .addSubcommandGroup(group =>
+ group
+ .setName('bans')
+ .setDescription('Global Ban List - Protect the network')
+ .addSubcommand(sub => sub.setName('add').setDescription('Add user to global ban list')
+ .addUserOption(opt => opt.setName('user').setDescription('User to ban').setRequired(true))
+ .addStringOption(opt => opt.setName('reason').setDescription('Reason for ban').setRequired(true))
+ .addStringOption(opt => opt.setName('severity').setDescription('Severity level')
+ .addChoices(
+ { name: 'Low - Minor offense', value: 'low' },
+ { name: 'Medium - Moderate offense', value: 'medium' },
+ { name: 'High - Serious offense', value: 'high' },
+ { name: 'Critical - Nuker/Scammer', value: 'critical' }
+ )))
+ .addSubcommand(sub => sub.setName('lookup').setDescription('Check if user is on global ban list')
+ .addUserOption(opt => opt.setName('user').setDescription('User to lookup').setRequired(true)))
+ .addSubcommand(sub => sub.setName('list').setDescription('View recent global bans'))
+ .addSubcommand(sub => sub.setName('remove').setDescription('Remove user from global ban list')
+ .addUserOption(opt => opt.setName('user').setDescription('User to remove').setRequired(true)))
)
- .addSubcommand(subcommand =>
- subcommand
- .setName('list')
- .setDescription('List all linked roles')
+ .addSubcommandGroup(group =>
+ group
+ .setName('servers')
+ .setDescription('Federation Server Directory')
+ .addSubcommand(sub => sub.setName('directory').setDescription('Browse all federation servers'))
+ .addSubcommand(sub => sub.setName('info').setDescription('View a specific server')
+ .addStringOption(opt => opt.setName('server').setDescription('Server name or ID').setRequired(true)))
+ .addSubcommand(sub => sub.setName('featured').setDescription('View featured servers'))
+ )
+ .addSubcommandGroup(group =>
+ group
+ .setName('membership')
+ .setDescription('Join or manage federation membership')
+ .addSubcommand(sub => sub.setName('apply').setDescription('Apply to join the federation')
+ .addStringOption(opt => opt.setName('category').setDescription('Server category')
+ .addChoices(
+ { name: 'Gaming', value: 'gaming' },
+ { name: 'Creative', value: 'creative' },
+ { name: 'Development', value: 'development' },
+ { name: 'Education', value: 'education' },
+ { name: 'Community', value: 'community' },
+ { name: 'Business', value: 'business' }
+ ).setRequired(true))
+ .addStringOption(opt => opt.setName('description').setDescription('Brief description of your server').setRequired(true)))
+ .addSubcommand(sub => sub.setName('status').setDescription('Check your server\'s federation status'))
+ .addSubcommand(sub => sub.setName('treaty').setDescription('View the Federation Treaty'))
+ )
+ .addSubcommandGroup(group =>
+ group
+ .setName('scouts')
+ .setDescription('Talent Scout - Cross-server reputation')
+ .addSubcommand(sub => sub.setName('leaderboard').setDescription('View global reputation leaderboard'))
+ .addSubcommand(sub => sub.setName('profile').setDescription('View cross-server profile')
+ .addUserOption(opt => opt.setName('user').setDescription('User to lookup')))
),
async execute(interaction, supabase, client) {
const mode = await getServerMode(supabase, interaction.guildId);
+ const group = interaction.options.getSubcommandGroup();
+ const subcommand = interaction.options.getSubcommand();
- if (mode === 'standalone') {
+ if (mode === 'standalone' && group !== 'membership') {
const embed = new EmbedBuilder()
.setColor(EMBED_COLORS.standalone)
- .setTitle('🏠 Standalone Mode')
- .setDescription('Federation features are disabled in standalone mode.\n\nThis server operates independently and does not sync roles across the AeThex network.\n\nUse `/config mode` to switch to federated mode.');
+ .setTitle('Standalone Mode')
+ .setDescription('Federation features are disabled in standalone mode.\n\nUse `/federation membership apply` to join the network, or `/config mode` to switch to federated mode.');
return interaction.reply({ embeds: [embed], ephemeral: true });
}
- const subcommand = interaction.options.getSubcommand();
-
- if (subcommand === 'link') {
- const role = interaction.options.getRole('role');
-
- const mappingData = {
- name: role.name,
- guildId: interaction.guildId,
- guildName: interaction.guild.name,
- linkedAt: Date.now(),
- };
- client.federationMappings.set(role.id, mappingData);
-
- if (client.saveFederationMapping) {
- await client.saveFederationMapping(role.id, mappingData);
- }
-
- const embed = new EmbedBuilder()
- .setColor(0x00ff00)
- .setTitle('Role Linked')
- .setDescription(`${role} is now linked for federation sync.`)
- .addFields(
- { name: 'Role ID', value: role.id, inline: true },
- { name: 'Server', value: interaction.guild.name, inline: true }
- )
- .setTimestamp();
-
- await interaction.reply({ embeds: [embed] });
- }
-
- if (subcommand === 'unlink') {
- const role = interaction.options.getRole('role');
-
- if (client.federationMappings.has(role.id)) {
- client.federationMappings.delete(role.id);
-
- if (client.deleteFederationMapping) {
- await client.deleteFederationMapping(role.id);
- }
-
- const embed = new EmbedBuilder()
- .setColor(0xff6600)
- .setTitle('Role Unlinked')
- .setDescription(`${role} has been removed from federation sync.`)
- .setTimestamp();
-
- await interaction.reply({ embeds: [embed] });
- } else {
- const embed = new EmbedBuilder()
- .setColor(0xff0000)
- .setTitle('Not Found')
- .setDescription(`${role} is not currently linked.`)
- .setTimestamp();
-
- await interaction.reply({ embeds: [embed], ephemeral: true });
- }
- }
-
- if (subcommand === 'list') {
- const mappings = [...client.federationMappings.entries()];
-
- if (mappings.length === 0) {
- const embed = new EmbedBuilder()
- .setColor(0x7c3aed)
- .setTitle('Federation Roles')
- .setDescription('No roles are currently linked for federation sync.\nUse `/federation link` to add roles.')
- .setTimestamp();
-
- await interaction.reply({ embeds: [embed] });
- return;
- }
-
- const roleList = mappings.map(([roleId, data]) =>
- `<@&${roleId}> - ${data.guildName}`
- ).join('\n');
-
- const embed = new EmbedBuilder()
- .setColor(0x7c3aed)
- .setTitle('Federation Roles')
- .setDescription(roleList)
- .setFooter({ text: `${mappings.length} role(s) linked` })
- .setTimestamp();
-
- await interaction.reply({ embeds: [embed] });
+ if (group === 'roles') {
+ await handleRoles(interaction, supabase, client, subcommand);
+ } else if (group === 'bans') {
+ await handleBans(interaction, supabase, client, subcommand);
+ } else if (group === 'servers') {
+ await handleServers(interaction, supabase, client, subcommand);
+ } else if (group === 'membership') {
+ await handleMembership(interaction, supabase, client, subcommand);
+ } else if (group === 'scouts') {
+ await handleScouts(interaction, supabase, client, subcommand);
}
},
};
+
+async function handleRoles(interaction, supabase, client, subcommand) {
+ if (subcommand === 'link') {
+ if (!interaction.member.permissions.has(PermissionFlagsBits.ManageRoles)) {
+ return interaction.reply({ content: 'You need Manage Roles permission.', ephemeral: true });
+ }
+
+ const role = interaction.options.getRole('role');
+ const mappingData = {
+ name: role.name,
+ guildId: interaction.guildId,
+ guildName: interaction.guild.name,
+ linkedAt: Date.now(),
+ };
+ client.federationMappings.set(role.id, mappingData);
+
+ if (client.saveFederationMapping) {
+ await client.saveFederationMapping(role.id, mappingData);
+ }
+
+ const embed = new EmbedBuilder()
+ .setColor(0x00ff00)
+ .setTitle('Role Linked')
+ .setDescription(`${role} is now linked for federation sync.`)
+ .addFields(
+ { name: 'Role ID', value: role.id, inline: true },
+ { name: 'Server', value: interaction.guild.name, inline: true }
+ )
+ .setTimestamp();
+
+ await interaction.reply({ embeds: [embed] });
+ }
+
+ if (subcommand === 'unlink') {
+ if (!interaction.member.permissions.has(PermissionFlagsBits.ManageRoles)) {
+ return interaction.reply({ content: 'You need Manage Roles permission.', ephemeral: true });
+ }
+
+ const role = interaction.options.getRole('role');
+
+ if (client.federationMappings.has(role.id)) {
+ client.federationMappings.delete(role.id);
+ if (client.deleteFederationMapping) {
+ await client.deleteFederationMapping(role.id);
+ }
+
+ const embed = new EmbedBuilder()
+ .setColor(0xff6600)
+ .setTitle('Role Unlinked')
+ .setDescription(`${role} has been removed from federation sync.`)
+ .setTimestamp();
+
+ await interaction.reply({ embeds: [embed] });
+ } else {
+ await interaction.reply({ content: `${role} is not currently linked.`, ephemeral: true });
+ }
+ }
+
+ if (subcommand === 'list') {
+ const mappings = [...client.federationMappings.entries()];
+
+ if (mappings.length === 0) {
+ const embed = new EmbedBuilder()
+ .setColor(0x7c3aed)
+ .setTitle('Federation Roles')
+ .setDescription('No roles are currently linked.\nUse `/federation roles link` to add roles.')
+ .setTimestamp();
+ return interaction.reply({ embeds: [embed] });
+ }
+
+ const roleList = mappings.map(([roleId, data]) =>
+ `<@&${roleId}> - ${data.guildName}`
+ ).join('\n');
+
+ const embed = new EmbedBuilder()
+ .setColor(0x7c3aed)
+ .setTitle('Federation Roles')
+ .setDescription(roleList)
+ .setFooter({ text: `${mappings.length} role(s) linked` })
+ .setTimestamp();
+
+ await interaction.reply({ embeds: [embed] });
+ }
+}
+
+async function handleBans(interaction, supabase, client, subcommand) {
+ if (!supabase) {
+ return interaction.reply({ content: 'Database not available.', ephemeral: true });
+ }
+
+ if (subcommand === 'add') {
+ if (!interaction.member.permissions.has(PermissionFlagsBits.BanMembers)) {
+ return interaction.reply({ content: 'You need Ban Members permission.', ephemeral: true });
+ }
+
+ const user = interaction.options.getUser('user');
+ const reason = interaction.options.getString('reason');
+ const severity = interaction.options.getString('severity') || 'medium';
+
+ const { data: existing } = await supabase
+ .from('federation_bans')
+ .select('id')
+ .eq('user_id', user.id)
+ .eq('active', true)
+ .maybeSingle();
+
+ if (existing) {
+ return interaction.reply({ content: `${user.tag} is already on the global ban list.`, ephemeral: true });
+ }
+
+ const { error } = await supabase.from('federation_bans').insert({
+ user_id: user.id,
+ username: user.tag,
+ reason,
+ severity,
+ banned_by_guild_id: interaction.guildId,
+ banned_by_user_id: interaction.user.id,
+ });
+
+ if (error) {
+ console.error('Federation ban error:', error);
+ return interaction.reply({ content: 'Failed to add ban.', ephemeral: true });
+ }
+
+ const severityColors = { low: 0xffff00, medium: 0xff9900, high: 0xff3300, critical: 0xff0000 };
+ const severityEmojis = { low: '⚠️', medium: '🔶', high: '🔴', critical: '☠️' };
+
+ const embed = new EmbedBuilder()
+ .setColor(severityColors[severity])
+ .setTitle(`${severityEmojis[severity]} Global Ban Added`)
+ .setThumbnail(user.displayAvatarURL())
+ .addFields(
+ { name: 'User', value: `${user.tag}\n\`${user.id}\``, inline: true },
+ { name: 'Severity', value: severity.toUpperCase(), inline: true },
+ { name: 'Reason', value: reason }
+ )
+ .setFooter({ text: `Added by ${interaction.user.tag}` })
+ .setTimestamp();
+
+ await interaction.reply({ embeds: [embed] });
+
+ await createBanAlerts(supabase, client, user.id, severity);
+ }
+
+ if (subcommand === 'lookup') {
+ const user = interaction.options.getUser('user');
+
+ const { data: ban } = await supabase
+ .from('federation_bans')
+ .select('*')
+ .eq('user_id', user.id)
+ .eq('active', true)
+ .maybeSingle();
+
+ if (!ban) {
+ const embed = new EmbedBuilder()
+ .setColor(0x00ff00)
+ .setTitle('User Clear')
+ .setThumbnail(user.displayAvatarURL())
+ .setDescription(`${user.tag} is **not** on the global ban list.`)
+ .setTimestamp();
+ return interaction.reply({ embeds: [embed] });
+ }
+
+ const severityColors = { low: 0xffff00, medium: 0xff9900, high: 0xff3300, critical: 0xff0000 };
+
+ const embed = new EmbedBuilder()
+ .setColor(severityColors[ban.severity])
+ .setTitle('User Flagged')
+ .setThumbnail(user.displayAvatarURL())
+ .addFields(
+ { name: 'User', value: `${user.tag}\n\`${user.id}\``, inline: true },
+ { name: 'Severity', value: ban.severity.toUpperCase(), inline: true },
+ { name: 'Reason', value: ban.reason },
+ { name: 'Banned On', value: new Date(ban.created_at).toLocaleDateString(), inline: true }
+ )
+ .setTimestamp();
+
+ await interaction.reply({ embeds: [embed] });
+ }
+
+ if (subcommand === 'list') {
+ const { data: bans } = await supabase
+ .from('federation_bans')
+ .select('*')
+ .eq('active', true)
+ .order('created_at', { ascending: false })
+ .limit(10);
+
+ if (!bans || bans.length === 0) {
+ return interaction.reply({ content: 'No active global bans.', ephemeral: true });
+ }
+
+ const severityEmojis = { low: '⚠️', medium: '🔶', high: '🔴', critical: '☠️' };
+
+ const banList = bans.map(b =>
+ `${severityEmojis[b.severity]} **${b.username || b.user_id}** - ${b.reason.substring(0, 50)}${b.reason.length > 50 ? '...' : ''}`
+ ).join('\n');
+
+ const embed = new EmbedBuilder()
+ .setColor(0xff0000)
+ .setTitle('Global Ban List')
+ .setDescription(banList)
+ .setFooter({ text: `Showing ${bans.length} most recent bans` })
+ .setTimestamp();
+
+ await interaction.reply({ embeds: [embed] });
+ }
+
+ if (subcommand === 'remove') {
+ if (!interaction.member.permissions.has(PermissionFlagsBits.Administrator)) {
+ return interaction.reply({ content: 'You need Administrator permission.', ephemeral: true });
+ }
+
+ const user = interaction.options.getUser('user');
+
+ const { error } = await supabase
+ .from('federation_bans')
+ .update({ active: false, updated_at: new Date().toISOString() })
+ .eq('user_id', user.id)
+ .eq('active', true);
+
+ if (error) {
+ return interaction.reply({ content: 'Failed to remove ban.', ephemeral: true });
+ }
+
+ const embed = new EmbedBuilder()
+ .setColor(0x00ff00)
+ .setTitle('Ban Removed')
+ .setDescription(`${user.tag} has been removed from the global ban list.`)
+ .setTimestamp();
+
+ await interaction.reply({ embeds: [embed] });
+ }
+}
+
+async function handleServers(interaction, supabase, client, subcommand) {
+ if (!supabase) {
+ return interaction.reply({ content: 'Database not available.', ephemeral: true });
+ }
+
+ if (subcommand === 'directory') {
+ const { data: servers } = await supabase
+ .from('federation_servers')
+ .select('*')
+ .eq('status', 'approved')
+ .order('member_count', { ascending: false })
+ .limit(15);
+
+ if (!servers || servers.length === 0) {
+ const embed = new EmbedBuilder()
+ .setColor(0x7c3aed)
+ .setTitle('Federation Directory')
+ .setDescription('No servers in the federation yet.\nUse `/federation membership apply` to be the first!')
+ .setTimestamp();
+ return interaction.reply({ embeds: [embed] });
+ }
+
+ const categoryEmojis = { gaming: '🎮', creative: '🎨', development: '💻', education: '📚', community: '👥', business: '🏢' };
+
+ const serverList = servers.map((s, i) => {
+ const emoji = categoryEmojis[s.category] || '🌐';
+ const featured = s.featured ? '⭐' : '';
+ return `${i + 1}. ${emoji} **${s.guild_name}** ${featured}\n ${s.member_count?.toLocaleString() || '?'} members • ${s.category || 'general'}`;
+ }).join('\n\n');
+
+ const embed = new EmbedBuilder()
+ .setColor(0x7c3aed)
+ .setTitle('Federation Directory')
+ .setDescription(serverList)
+ .setFooter({ text: `${servers.length} servers in the federation` })
+ .setTimestamp();
+
+ await interaction.reply({ embeds: [embed] });
+ }
+
+ if (subcommand === 'info') {
+ const serverQuery = interaction.options.getString('server');
+
+ const { data: server } = await supabase
+ .from('federation_servers')
+ .select('*')
+ .or(`guild_id.eq.${serverQuery},guild_name.ilike.%${serverQuery}%`)
+ .eq('status', 'approved')
+ .maybeSingle();
+
+ if (!server) {
+ return interaction.reply({ content: 'Server not found in the federation.', ephemeral: true });
+ }
+
+ const embed = new EmbedBuilder()
+ .setColor(0x7c3aed)
+ .setTitle(server.guild_name)
+ .setDescription(server.description || 'No description provided.')
+ .addFields(
+ { name: 'Members', value: server.member_count?.toLocaleString() || 'Unknown', inline: true },
+ { name: 'Category', value: server.category || 'General', inline: true },
+ { name: 'Tier', value: server.tier?.toUpperCase() || 'FREE', inline: true },
+ { name: 'Joined Federation', value: new Date(server.joined_at).toLocaleDateString(), inline: true }
+ )
+ .setTimestamp();
+
+ if (server.guild_icon) {
+ embed.setThumbnail(`https://cdn.discordapp.com/icons/${server.guild_id}/${server.guild_icon}.png`);
+ }
+
+ await interaction.reply({ embeds: [embed] });
+ }
+
+ if (subcommand === 'featured') {
+ const { data: featured } = await supabase
+ .from('federation_servers')
+ .select('*')
+ .eq('featured', true)
+ .eq('status', 'approved');
+
+ if (!featured || featured.length === 0) {
+ return interaction.reply({ content: 'No featured servers at this time.', ephemeral: true });
+ }
+
+ const serverList = featured.map(s =>
+ `⭐ **${s.guild_name}**\n${s.description?.substring(0, 100) || 'No description'}${s.description?.length > 100 ? '...' : ''}`
+ ).join('\n\n');
+
+ const embed = new EmbedBuilder()
+ .setColor(0xffd700)
+ .setTitle('Featured Servers')
+ .setDescription(serverList)
+ .setTimestamp();
+
+ await interaction.reply({ embeds: [embed] });
+ }
+}
+
+async function handleMembership(interaction, supabase, client, subcommand) {
+ if (!supabase) {
+ return interaction.reply({ content: 'Database not available.', ephemeral: true });
+ }
+
+ if (subcommand === 'apply') {
+ if (!interaction.member.permissions.has(PermissionFlagsBits.Administrator)) {
+ return interaction.reply({ content: 'Only administrators can apply to the federation.', ephemeral: true });
+ }
+
+ const { data: existing } = await supabase
+ .from('federation_servers')
+ .select('status')
+ .eq('guild_id', interaction.guildId)
+ .maybeSingle();
+
+ if (existing) {
+ return interaction.reply({ content: `Your server is already ${existing.status} in the federation.`, ephemeral: true });
+ }
+
+ const { data: pendingApp } = await supabase
+ .from('federation_applications')
+ .select('status')
+ .eq('guild_id', interaction.guildId)
+ .maybeSingle();
+
+ if (pendingApp) {
+ return interaction.reply({ content: `Application already ${pendingApp.status}. Use /federation membership status to check.`, ephemeral: true });
+ }
+
+ const category = interaction.options.getString('category');
+ const description = interaction.options.getString('description');
+
+ const { error } = await supabase.from('federation_applications').insert({
+ guild_id: interaction.guildId,
+ guild_name: interaction.guild.name,
+ guild_icon: interaction.guild.icon,
+ member_count: interaction.guild.memberCount,
+ category,
+ description,
+ admin_id: interaction.user.id,
+ admin_username: interaction.user.tag,
+ treaty_agreed: true,
+ });
+
+ if (error) {
+ console.error('Federation application error:', error);
+ return interaction.reply({ content: 'Failed to submit application.', ephemeral: true });
+ }
+
+ const embed = new EmbedBuilder()
+ .setColor(0x00ff00)
+ .setTitle('Application Submitted')
+ .setDescription('Your server has been submitted for federation membership!')
+ .addFields(
+ { name: 'Server', value: interaction.guild.name, inline: true },
+ { name: 'Category', value: category, inline: true },
+ { name: 'Status', value: 'Pending Review', inline: true }
+ )
+ .setFooter({ text: 'You will be notified when your application is reviewed.' })
+ .setTimestamp();
+
+ await interaction.reply({ embeds: [embed] });
+ }
+
+ if (subcommand === 'status') {
+ const { data: server } = await supabase
+ .from('federation_servers')
+ .select('*')
+ .eq('guild_id', interaction.guildId)
+ .maybeSingle();
+
+ if (server) {
+ const embed = new EmbedBuilder()
+ .setColor(0x00ff00)
+ .setTitle('Federation Member')
+ .addFields(
+ { name: 'Status', value: server.status.toUpperCase(), inline: true },
+ { name: 'Tier', value: server.tier?.toUpperCase() || 'FREE', inline: true },
+ { name: 'Joined', value: new Date(server.joined_at).toLocaleDateString(), inline: true }
+ )
+ .setTimestamp();
+ return interaction.reply({ embeds: [embed] });
+ }
+
+ const { data: application } = await supabase
+ .from('federation_applications')
+ .select('*')
+ .eq('guild_id', interaction.guildId)
+ .maybeSingle();
+
+ if (application) {
+ const statusColors = { pending: 0xffff00, approved: 0x00ff00, rejected: 0xff0000 };
+ const embed = new EmbedBuilder()
+ .setColor(statusColors[application.status] || 0x7c3aed)
+ .setTitle('Application Status')
+ .addFields(
+ { name: 'Status', value: application.status.toUpperCase(), inline: true },
+ { name: 'Submitted', value: new Date(application.created_at).toLocaleDateString(), inline: true }
+ )
+ .setTimestamp();
+
+ if (application.rejection_reason) {
+ embed.addFields({ name: 'Reason', value: application.rejection_reason });
+ }
+
+ return interaction.reply({ embeds: [embed] });
+ }
+
+ const embed = new EmbedBuilder()
+ .setColor(0x7c3aed)
+ .setTitle('Not a Member')
+ .setDescription('This server is not in the federation.\nUse `/federation membership apply` to join!')
+ .setTimestamp();
+
+ await interaction.reply({ embeds: [embed] });
+ }
+
+ if (subcommand === 'treaty') {
+ const embed = new EmbedBuilder()
+ .setColor(0x7c3aed)
+ .setTitle('The AeThex Federation Treaty')
+ .setDescription('By joining the Federation, your server agrees to:')
+ .addFields(
+ { name: '1. Contribute to Global Safety', value: 'Report nukers, scammers, and bad actors to the Global Ban List.' },
+ { name: '2. Maintain Standards', value: 'Uphold basic moderation and community guidelines.' },
+ { name: '3. Respect the Network', value: 'Do not exploit federation features or share protected data.' },
+ { name: '4. Display Membership', value: 'Optionally display Federation badge to verify authenticity.' }
+ )
+ .setFooter({ text: 'Together, we are untouchable.' })
+ .setTimestamp();
+
+ const row = new ActionRowBuilder()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId('federation_agree_treaty')
+ .setLabel('I Agree')
+ .setStyle(ButtonStyle.Success),
+ new ButtonBuilder()
+ .setLabel('Learn More')
+ .setStyle(ButtonStyle.Link)
+ .setURL('https://aethex.dev/federation')
+ );
+
+ await interaction.reply({ embeds: [embed], components: [row] });
+ }
+}
+
+async function handleScouts(interaction, supabase, client, subcommand) {
+ if (!supabase) {
+ return interaction.reply({ content: 'Database not available.', ephemeral: true });
+ }
+
+ if (subcommand === 'leaderboard') {
+ const { data: leaders } = await supabase
+ .from('federation_reputation')
+ .select('*')
+ .order('reputation_score', { ascending: false })
+ .limit(15);
+
+ if (!leaders || leaders.length === 0) {
+ const embed = new EmbedBuilder()
+ .setColor(0x7c3aed)
+ .setTitle('Federation Leaderboard')
+ .setDescription('No reputation data yet. Be active across federation servers to appear here!')
+ .setTimestamp();
+ return interaction.reply({ embeds: [embed] });
+ }
+
+ const tierEmojis = { newcomer: '🌱', member: '⭐', veteran: '🏆', elite: '💎', legend: '👑' };
+
+ const leaderList = leaders.map((l, i) => {
+ const emoji = tierEmojis[l.rank_tier] || '🌱';
+ const medal = i === 0 ? '🥇' : i === 1 ? '🥈' : i === 2 ? '🥉' : `${i + 1}.`;
+ return `${medal} ${emoji} <@${l.discord_id}> - **${l.reputation_score?.toLocaleString() || 0}** rep`;
+ }).join('\n');
+
+ const embed = new EmbedBuilder()
+ .setColor(0xffd700)
+ .setTitle('Federation Leaderboard')
+ .setDescription(leaderList)
+ .setFooter({ text: 'Reputation earned across all federation servers' })
+ .setTimestamp();
+
+ await interaction.reply({ embeds: [embed] });
+ }
+
+ if (subcommand === 'profile') {
+ const user = interaction.options.getUser('user') || interaction.user;
+
+ const { data: rep } = await supabase
+ .from('federation_reputation')
+ .select('*')
+ .eq('discord_id', user.id)
+ .maybeSingle();
+
+ if (!rep) {
+ const embed = new EmbedBuilder()
+ .setColor(0x7c3aed)
+ .setTitle('No Federation Profile')
+ .setDescription(`${user.tag} doesn't have a federation profile yet.\nBe active across federation servers to build reputation!`)
+ .setTimestamp();
+ return interaction.reply({ embeds: [embed] });
+ }
+
+ const tierEmojis = { newcomer: '🌱', member: '⭐', veteran: '🏆', elite: '💎', legend: '👑' };
+
+ const embed = new EmbedBuilder()
+ .setColor(0x7c3aed)
+ .setTitle(`${user.tag}'s Federation Profile`)
+ .setThumbnail(user.displayAvatarURL())
+ .addFields(
+ { name: 'Reputation', value: rep.reputation_score?.toLocaleString() || '0', inline: true },
+ { name: 'Rank', value: `${tierEmojis[rep.rank_tier] || '🌱'} ${rep.rank_tier?.toUpperCase() || 'NEWCOMER'}`, inline: true },
+ { name: 'Active In', value: `${rep.servers_active_in || 0} servers`, inline: true },
+ { name: 'Total XP', value: rep.total_xp?.toLocaleString() || '0', inline: true },
+ { name: 'Highest Level', value: `${rep.highest_level || 0}`, inline: true },
+ { name: 'Prestige', value: `${rep.prestige_total || 0}`, inline: true }
+ )
+ .setFooter({ text: `Last active: ${rep.last_active ? new Date(rep.last_active).toLocaleDateString() : 'Unknown'}` })
+ .setTimestamp();
+
+ if (rep.badges && rep.badges.length > 0) {
+ embed.addFields({ name: 'Badges', value: rep.badges.join(' ') });
+ }
+
+ await interaction.reply({ embeds: [embed] });
+ }
+}
+
+async function createBanAlerts(supabase, client, userId, severity) {
+ try {
+ const { data: servers } = await supabase
+ .from('federation_servers')
+ .select('guild_id, tier')
+ .eq('status', 'approved');
+
+ if (!servers) return;
+
+ const alerts = servers
+ .filter(s => severity === 'critical' || s.tier === 'premium')
+ .map(s => ({
+ guild_id: s.guild_id,
+ alert_type: 'new_ban',
+ }));
+
+ if (alerts.length > 0) {
+ const { data: ban } = await supabase
+ .from('federation_bans')
+ .select('id')
+ .eq('user_id', userId)
+ .eq('active', true)
+ .maybeSingle();
+
+ if (ban) {
+ const alertsWithBanId = alerts.map(a => ({ ...a, ban_id: ban.id }));
+ await supabase.from('federation_alerts').insert(alertsWithBanId);
+ }
+ }
+ } catch (err) {
+ console.error('Error creating ban alerts:', err);
+ }
+}
diff --git a/aethex-bot/listeners/federationProtection.js b/aethex-bot/listeners/federationProtection.js
new file mode 100644
index 0000000..04413e4
--- /dev/null
+++ b/aethex-bot/listeners/federationProtection.js
@@ -0,0 +1,118 @@
+const { EmbedBuilder } = require('discord.js');
+
+module.exports = {
+ name: 'guildMemberAdd',
+
+ async execute(member, client, supabase) {
+ if (!supabase) return;
+
+ try {
+ const { data: serverConfig } = await supabase
+ .from('federation_servers')
+ .select('tier, status')
+ .eq('guild_id', member.guild.id)
+ .eq('status', 'approved')
+ .maybeSingle();
+
+ if (!serverConfig) return;
+
+ const { data: ban } = await supabase
+ .from('federation_bans')
+ .select('*')
+ .eq('user_id', member.id)
+ .eq('active', true)
+ .maybeSingle();
+
+ if (!ban) return;
+
+ const isPremium = serverConfig.tier === 'premium';
+ const isCritical = ban.severity === 'critical';
+
+ if (!isPremium && !isCritical) {
+ return;
+ }
+
+ const severityColors = { low: 0xffff00, medium: 0xff9900, high: 0xff3300, critical: 0xff0000 };
+ const severityEmojis = { low: '⚠️', medium: '🔶', high: '🔴', critical: '☠️' };
+
+ const alertEmbed = new EmbedBuilder()
+ .setColor(severityColors[ban.severity])
+ .setTitle(`${severityEmojis[ban.severity]} Federation Alert: Flagged User Joined`)
+ .setThumbnail(member.displayAvatarURL())
+ .addFields(
+ { name: 'User', value: `${member.user.tag}\n\`${member.id}\``, inline: true },
+ { name: 'Severity', value: ban.severity.toUpperCase(), inline: true },
+ { name: 'Reason', value: ban.reason || 'No reason provided' }
+ )
+ .setFooter({ text: 'AeThex Federation Protection' })
+ .setTimestamp();
+
+ const { data: config } = await supabase
+ .from('server_config')
+ .select('modlog_channel')
+ .eq('guild_id', member.guild.id)
+ .maybeSingle();
+
+ if (config?.modlog_channel) {
+ const logChannel = await client.channels.fetch(config.modlog_channel).catch(() => null);
+ if (logChannel) {
+ await logChannel.send({ embeds: [alertEmbed] });
+ }
+ }
+
+ if (isCritical) {
+ try {
+ await member.ban({ reason: `[Federation] Global ban: ${ban.reason}` });
+
+ alertEmbed.setTitle(`${severityEmojis[ban.severity]} Federation Auto-Ban: Critical Threat Removed`);
+ alertEmbed.addFields({ name: 'Action Taken', value: 'User was automatically banned' });
+
+ await supabase.from('federation_alerts').update({
+ delivered: true,
+ delivered_at: new Date().toISOString(),
+ action_taken: 'auto_ban'
+ }).eq('guild_id', member.guild.id).eq('ban_id', ban.id);
+
+ } catch (banError) {
+ console.error('[Federation] Failed to auto-ban:', banError.message);
+ alertEmbed.addFields({ name: 'Action Required', value: 'Auto-ban failed. Please ban manually.' });
+ }
+ } else if (isPremium) {
+ try {
+ await member.kick(`[Federation] Global ban (${ban.severity} severity): ${ban.reason}`);
+ alertEmbed.addFields({ name: 'Action Taken', value: 'User was automatically kicked (Premium Protection)' });
+
+ await supabase.from('federation_alerts').update({
+ delivered: true,
+ delivered_at: new Date().toISOString(),
+ action_taken: 'auto_kick'
+ }).eq('guild_id', member.guild.id).eq('ban_id', ban.id);
+ } catch (kickError) {
+ console.error('[Federation] Failed to auto-kick:', kickError.message);
+ alertEmbed.addFields({ name: 'Action Required', value: 'Auto-kick failed. Please remove user manually.' });
+ }
+ }
+
+ const owner = await member.guild.fetchOwner().catch(() => null);
+ if (owner && ban.severity === 'critical') {
+ try {
+ const dmEmbed = new EmbedBuilder()
+ .setColor(0xff0000)
+ .setTitle('Federation Alert: Critical Threat')
+ .setDescription(`A user on the global ban list (Critical severity) joined **${member.guild.name}** and was automatically banned.`)
+ .addFields(
+ { name: 'User', value: `${member.user.tag} (\`${member.id}\`)` },
+ { name: 'Reason', value: ban.reason }
+ )
+ .setTimestamp();
+
+ await owner.send({ embeds: [dmEmbed] });
+ } catch (dmError) {
+ }
+ }
+
+ } catch (error) {
+ console.error('[Federation Protection] Error:', error.message);
+ }
+ },
+};
diff --git a/aethex-bot/public/federation.html b/aethex-bot/public/federation.html
new file mode 100644
index 0000000..14d3c1a
--- /dev/null
+++ b/aethex-bot/public/federation.html
@@ -0,0 +1,625 @@
+
+
+
+
+
+ Federation - AeThex | Warden
+
+
+
+
+
+
+
+
+
+
+
The Federation
+
A network of protected servers. Ban one, ban all.
+
+
+
+
+
+
+
+
+
-
+
Pending Applications
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | User |
+ Severity |
+ Reason |
+ Date |
+
+
+
+ | Loading bans... |
+
+
+
+
+
+
+
+
+
+
+
+ | Server |
+ Category |
+ Members |
+ Status |
+ Actions |
+
+
+
+ | Loading applications... |
+
+
+
+
+
+
+
+
+
+
Loading leaderboard...
+
+
+
+
+
+
+
+
+
diff --git a/aethex-bot/server/webServer.js b/aethex-bot/server/webServer.js
index 65be149..f799337 100644
--- a/aethex-bot/server/webServer.js
+++ b/aethex-bot/server/webServer.js
@@ -1038,6 +1038,192 @@ function createWebServer(discordClient, supabase, options = {}) {
}
});
+ // ============ FEDERATION API ============
+
+ app.get('/api/federation/stats', async (req, res) => {
+ if (!supabase) {
+ return res.status(503).json({ error: 'Database not available' });
+ }
+
+ try {
+ const [servers, bans, applications] = await Promise.all([
+ supabase.from('federation_servers').select('id', { count: 'exact' }).eq('status', 'approved'),
+ supabase.from('federation_bans').select('id', { count: 'exact' }).eq('active', true),
+ supabase.from('federation_applications').select('id', { count: 'exact' }).eq('status', 'pending')
+ ]);
+
+ res.json({
+ totalServers: servers.count || 0,
+ activeBans: bans.count || 0,
+ pendingApplications: applications.count || 0
+ });
+ } catch (error) {
+ res.status(500).json({ error: 'Failed to fetch stats' });
+ }
+ });
+
+ app.get('/api/federation/bans', async (req, res) => {
+ if (!supabase) {
+ return res.status(503).json({ error: 'Database not available' });
+ }
+
+ const { limit = 50, severity } = req.query;
+
+ try {
+ let query = supabase
+ .from('federation_bans')
+ .select('*')
+ .eq('active', true)
+ .order('created_at', { ascending: false })
+ .limit(parseInt(limit));
+
+ if (severity) {
+ query = query.eq('severity', severity);
+ }
+
+ const { data: bans } = await query;
+ res.json({ bans: bans || [] });
+ } catch (error) {
+ res.status(500).json({ error: 'Failed to fetch bans' });
+ }
+ });
+
+ app.get('/api/federation/servers', async (req, res) => {
+ if (!supabase) {
+ return res.status(503).json({ error: 'Database not available' });
+ }
+
+ try {
+ const { data: servers } = await supabase
+ .from('federation_servers')
+ .select('*')
+ .eq('status', 'approved')
+ .order('member_count', { ascending: false });
+
+ res.json({ servers: servers || [] });
+ } catch (error) {
+ res.status(500).json({ error: 'Failed to fetch servers' });
+ }
+ });
+
+ app.get('/api/federation/applications', async (req, res) => {
+ if (!supabase) {
+ return res.status(503).json({ error: 'Database not available' });
+ }
+
+ const userId = req.session.user?.id;
+ if (!userId) {
+ return res.status(401).json({ error: 'Not authenticated' });
+ }
+
+ try {
+ const { data: applications } = await supabase
+ .from('federation_applications')
+ .select('*')
+ .order('created_at', { ascending: false });
+
+ res.json({ applications: applications || [] });
+ } catch (error) {
+ res.status(500).json({ error: 'Failed to fetch applications' });
+ }
+ });
+
+ app.post('/api/federation/applications/:appId/approve', async (req, res) => {
+ if (!supabase) {
+ return res.status(503).json({ error: 'Database not available' });
+ }
+
+ const userId = req.session.user?.id;
+ if (!userId) {
+ return res.status(401).json({ error: 'Not authenticated' });
+ }
+
+ const { appId } = req.params;
+
+ try {
+ const { data: app } = await supabase
+ .from('federation_applications')
+ .select('*')
+ .eq('id', appId)
+ .maybeSingle();
+
+ if (!app) {
+ return res.status(404).json({ error: 'Application not found' });
+ }
+
+ await supabase.from('federation_applications').update({
+ status: 'approved',
+ reviewed_by: userId,
+ reviewed_at: new Date().toISOString()
+ }).eq('id', appId);
+
+ await supabase.from('federation_servers').insert({
+ guild_id: app.guild_id,
+ guild_name: app.guild_name,
+ guild_icon: app.guild_icon,
+ description: app.description,
+ category: app.category,
+ member_count: app.member_count,
+ owner_id: app.admin_id,
+ status: 'approved',
+ treaty_accepted: true,
+ treaty_accepted_at: new Date().toISOString()
+ });
+
+ res.json({ success: true });
+ } catch (error) {
+ console.error('Failed to approve application:', error);
+ res.status(500).json({ error: 'Failed to approve application' });
+ }
+ });
+
+ app.post('/api/federation/applications/:appId/reject', async (req, res) => {
+ if (!supabase) {
+ return res.status(503).json({ error: 'Database not available' });
+ }
+
+ const userId = req.session.user?.id;
+ if (!userId) {
+ return res.status(401).json({ error: 'Not authenticated' });
+ }
+
+ const { appId } = req.params;
+ const { reason } = req.body;
+
+ try {
+ await supabase.from('federation_applications').update({
+ status: 'rejected',
+ reviewed_by: userId,
+ reviewed_at: new Date().toISOString(),
+ rejection_reason: reason || 'No reason provided'
+ }).eq('id', appId);
+
+ res.json({ success: true });
+ } catch (error) {
+ res.status(500).json({ error: 'Failed to reject application' });
+ }
+ });
+
+ app.get('/api/federation/leaderboard', async (req, res) => {
+ if (!supabase) {
+ return res.status(503).json({ error: 'Database not available' });
+ }
+
+ const { limit = 50 } = req.query;
+
+ try {
+ const { data: leaders } = await supabase
+ .from('federation_reputation')
+ .select('*')
+ .order('reputation_score', { ascending: false })
+ .limit(parseInt(limit));
+
+ res.json({ leaderboard: leaders || [] });
+ } catch (error) {
+ res.status(500).json({ error: 'Failed to fetch leaderboard' });
+ }
+ });
+
app.get('/health', (req, res) => {
res.json({
status: 'ok',
@@ -1046,6 +1232,10 @@ function createWebServer(discordClient, supabase, options = {}) {
});
});
+ app.get('/federation', (req, res) => {
+ res.sendFile(path.join(__dirname, '../public/federation.html'));
+ });
+
app.get('/dashboard', (req, res) => {
res.sendFile(path.join(__dirname, '../public/dashboard.html'));
});
diff --git a/attached_assets/Pasted-This-is-a-Network-Effect-strategy-You-aren-t-selling-th_1765329237794.txt b/attached_assets/Pasted-This-is-a-Network-Effect-strategy-You-aren-t-selling-th_1765329237794.txt
new file mode 100644
index 0000000..687e6d1
--- /dev/null
+++ b/attached_assets/Pasted-This-is-a-Network-Effect-strategy-You-aren-t-selling-th_1765329237794.txt
@@ -0,0 +1,46 @@
+This is a Network Effect strategy. You aren't selling the code; you are selling Membership.
+
+If the AeThex | Warden bot allows external servers to "Join the Federation," you are essentially building a Digital Alliance (like NATO or the United Nations of Roblox).
+
+Here is how you extract massive value (money, power, and data) from letting other servers join your Federation.
+
+1. The "Global Ban List" (Data Supremacy)
+The Mechanism: When a Federation server bans a user for being a "Nuker" or "Scammer," that ID is pushed to your central Supabase database.
+
+The Benefit: You build the ultimate Global Blacklist.
+
+The Monetization:
+
+Free Tier: Servers contribute bans but only get protection from "High Risk" nukers.
+
+Paid Tier ($50/mo): Servers get real-time protection from all Federation bans. "Protect your server from scammers before they even join."
+
+2. The "Cross-Pollination" (Traffic)
+The Mechanism: The bot includes a /federation directory or a "Featured Server" channel that is synced across all Federation members.
+
+The Benefit: Free advertising for your projects (Lone Star).
+
+The Monetization: You can charge member servers for "Featured Spots."
+
+Example: "Want your game promoted to the 50,000 users across the entire Federation network? That's $200/week."
+
+3. The "Diplomatic" Leverage (Power)
+The Mechanism: To join the Federation, a server admin must agree to your "Treaty" (Terms of Service).
+
+The Benefit: You become the Standard Setter.
+
+The Strategy: If a studio wants to be in the Federation (to look safe/official), they have to use your standards. This positions AeThex as the "Governing Body" of the alliance. It elevates your brand from "Studio" to "Authority."
+
+4. The "Talent Scout" (Recruitment)
+The Mechanism: With Federation Sync, you can see high-level users across all connected servers.
+
+The Benefit: You can identify top developers or active users in other people's servers.
+
+The Strategy: If you see a user who is Level 50 in three different Federation coding servers, you know they are legit. You can invite them to StarFoundry directly.
+
+Summary: How to Pitch It
+You don't sell the bot. You sell Safety in Numbers.
+
+"Join the AeThex Federation. When a nuker attacks one of us, they are banned from all of us instantly. Together, we are untouchable."
+
+Verdict: This is the smartest "Long Game" move. It costs you nothing but server fees, but it builds a massive defensive network that you control.
\ No newline at end of file