import { Result } from "@sapphire/result"; import { editActor, getActor } from "@stealth-developers/db"; import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js"; import { logger } from "@/lib"; import { useGetData } from "@/middleware"; import { client } from "../roblox/client"; export const syncCommand = useGetData.command("sync", { description: "Link your Roblox account to your Discord account", }); syncCommand.subcommand("pair", { description: "Link your Roblox account to your Discord account", run: async (interaction, _, { actor }) => { if (!actor) return interaction.reply({ content: "Failed to fetch your data.", ephemeral: true }); const pin = Math.floor(100000 + Math.random() * 900000); const pinExpiryMs = 5 * 60 * 1000; await editActor(actor.id, { pin: String(pin), pinExpiresIn: new Date(Date.now() + pinExpiryMs), }); interaction.reply({ content: [ `Your pin is: **${pin}**.`, "Input this pin in Ground War or Warfare Tycoon to link your account.", ].join(" "), flags: ["Ephemeral"], }); const pollIntervalMs = 5000; const startTime = Date.now(); const interval = setInterval(async () => { try { if (Date.now() - startTime > pinExpiryMs) { clearInterval(interval); await interaction .editReply({ content: "Your verification pin has expired. Please run the command again to generate a new one.", }) .catch(() => {}); return; } const updatedActor = await getActor(actor.id); if (updatedActor && updatedActor.robloxId) { clearInterval(interval); const oauthButton = new ButtonBuilder() .setLabel("Finalize Profile Sync") .setStyle(ButtonStyle.Link) .setURL(`http://127.0.0.1:3000/auth/login?actorId=${actor.id}`); const row = new ActionRowBuilder().addComponents(oauthButton); await interaction .editReply({ content: "Successfully linked your Roblox account! Click the button below to authorize game widgets on your Discord profile.", components: [row], }) .catch(() => {}); } } catch (error) { logger.error(error, "Error during pin verification polling"); } }, pollIntervalMs); }, }); syncCommand.subcommand("unlink", { description: "Unlink your Roblox account from your Discord account", run: async (interaction, _, { actor }) => { if (!actor) return interaction.reply({ content: "Failed to fetch your data.", flags: ["Ephemeral"] }); await editActor(actor.id, { pin: null, pinExpiresIn: null, robloxId: null, }); interaction.reply({ content: "Your account has been unlinked.", flags: ["Ephemeral"] }); }, }); syncCommand.subcommand("status", { description: "Check your linked Roblox account", run: async (interaction, _, { actor }) => { if (!actor) return interaction.reply({ content: "Failed to fetch your data.", flags: ["Ephemeral"] }); if (!actor.robloxId) return interaction.reply({ content: "You are not linked to a Roblox account.", flags: ["Ephemeral"], }); const accountRes = await Result.fromAsync(client.getUserProfile(actor.robloxId)); if (accountRes.isErr()) return interaction.reply({ content: "Failed to fetch your Roblox account.", flags: ["Ephemeral"], }); const account = accountRes.unwrap(); interaction.reply({ content: `You are linked to Roblox account **@${account.name}**.`, flags: ["Ephemeral"], }); }, });