import { Client, Guild, Invite, GuildMember } from 'discord.js'; import { redis } from '../cache'; import { prisma } from '../database'; import { logger } from '../utils/logger'; export class InviteService { public static async cacheAllInvites(client: Client) { for (const [, guild] of client.guilds.cache) { await this.cacheGuildInvites(guild); } logger.info('InviteMaster: Finished caching all invites.'); } public static async cacheGuildInvites(guild: Guild) { try { const invites = await guild.invites.fetch(); const inviteData = invites.map(inv => ({ code: inv.code, uses: inv.uses || 0 })); await redis.set(`invites:${guild.id}`, JSON.stringify(inviteData)); } catch (error) { logger.error(`InviteMaster: Failed to cache invites for guild ${guild.id}:`, error); } } public static async handleInviteCreate(invite: Invite) { if (!invite.guild) return; logger.debug(`InviteMaster: New invite created: ${invite.code}`); await this.cacheGuildInvites(invite.guild as Guild); } public static async handleInviteDelete(invite: Invite) { if (!invite.guild) return; logger.debug(`InviteMaster: Invite deleted: ${invite.code}`); await this.cacheGuildInvites(invite.guild as Guild); } public static async handleMemberAdd(member: GuildMember) { const guild = member.guild; try { // Fetch current active invites const newInvites = await guild.invites.fetch(); const cachedData = await redis.get(`invites:${guild.id}`); let usedInvite: Invite | undefined; if (cachedData) { const cachedInvites: { code: string, uses: number }[] = JSON.parse(cachedData); // Find the invite where 'uses' has increased usedInvite = newInvites.find(inv => { const cached = cachedInvites.find(c => c.code === inv.code); return cached ? (inv.uses || 0) > cached.uses : false; }); } // Update the cache immediately to account for this new join await this.cacheGuildInvites(guild); if (usedInvite) { logger.info(`InviteMaster: ${member.user.tag} joined using invite ${usedInvite.code}`); // Check DB for mapped role const inviteRole = await prisma.inviteRole.findFirst({ where: { guildId: guild.id, inviteCode: usedInvite.code } }); if (inviteRole) { const role = guild.roles.cache.get(inviteRole.roleId); if (role) { await member.roles.add(role); logger.info(`InviteMaster: Assigned role ${role.name} to ${member.user.tag}`); } else { logger.warn(`InviteMaster: Role ${inviteRole.roleId} mapped to invite ${usedInvite.code} not found.`); } } } else { logger.info(`InviteMaster: ${member.user.tag} joined but invite could not be determined (ex: Vanity URL).`); } } catch (error) { logger.error(`InviteMaster: Failed to handle member add tracking:`, error); } } }