1- / **
2- * 🏺 Ritual Scroll: badgeEmitter.ts
3- * Description: Listens for sponsorPing events, logs relic drops, and broadcasts
4- * badge-ceremony embeds across configured Discord channels.
5- * /
6-
7- import { Client, GatewayIntentBits, TextChannel, ThreadChannel, ChannelType } from 'discord.js';
1+ import {
2+ Client,
3+ GatewayIntentBits,
4+ TextChannel,
5+ ThreadChannel,
6+ ChannelType
7+ } from 'discord.js';
88import { BadgeClient } from 'kypria-badge-sdk';
99import { promises as fs } from 'fs';
1010import path from 'path';
@@ -28,62 +28,58 @@ type Relic = SponsorPingPayload & {
2828};
2929
3030(async () => {
31- // 1️⃣ Load & validate badge-locations.yml
31+ // Load badge config
3232 const cfgPath = path.resolve(__ dirname, '../config/badge-locations.yml');
3333 let config: Config = {};
34-
3534 try {
3635 const raw = await fs.readFile(cfgPath, 'utf8');
3736 config = (yaml.load(raw) as Config) ?? {};
3837 } catch (err) {
39- console.error('❌ Failed to load badge-locations.yml:', err);
38+ console.error('❌ badge-locations.yml failed to load :', err);
4039 process.exit(1);
4140 }
4241
43- // 2️⃣ Initialize clients
42+ // Initialize clients
4443 const badgeClient = new BadgeClient({ apiToken: process.env.BADGE_API_TOKEN! });
45- const discord = new Client({ intents: [ GatewayIntentBits.Guilds] });
44+ const discord = new Client({ intents: [ GatewayIntentBits.Guilds] });
4645
4746 discord.once('ready', () => {
48- console.log(` ✅ Discord bot ready as ${discord.user?.tag} ` );
47+ console.log(` ✅ Discord bot logged in as ${discord.user?.tag} ` );
4948 });
5049
51- // 3️⃣ Handle sponsorPing events
50+ // Handle sponsorPing
5251 badgeClient.on('sponsorPing', async ({ sponsorId, badgeName }: SponsorPingPayload) => {
53- const channels = config[ badgeName] ?.drop_channels ?? [ ] ;
52+ const channels = config[ badgeName] ?.drop_channels ?? [ ] ;
5453 const timestamp = new Date().toISOString();
55- const threadId = ` thread-${timestamp.replace(/[:.]/g, '-')} ` ;
54+ const threadId = ` thread-${timestamp.replace(/[:.]/g, '-')} ` ;
5655 const relic: Relic = { sponsorId, badgeName, timestamp, threadId };
5756
58- // 3a️⃣ Audit-log the relic
59- const logDir = path.resolve(__dirname, '../threads');
57+ // Write audit log
58+ const logDir = path.resolve(__dirname, '../threads');
6059 await fs.mkdir(logDir, { recursive: true });
61- const fileName = `relic-drop--${badgeName}--${timestamp}.json`;
62- const outPath = path.join(logDir, fileName);
63- await fs.writeFile(outPath, JSON.stringify(relic, null, 2));
60+ const logPath = path.join(logDir, `relic-drop--${badgeName}--${timestamp}.json`);
61+ await fs.writeFile(logPath, JSON.stringify(relic, null, 2));
6462
65- // 3b️⃣ Broadcast the badge ceremony
63+ // Broadcast drop
6664 for (const chId of channels) {
6765 try {
6866 const channel = await discord.channels.fetch(chId);
6967 if (
7068 channel &&
71- (channel.type === ChannelType.GuildText ||
72- channel.type === ChannelType.GuildPublicThread)
69+ (channel.type === ChannelType.GuildText || channel.type === ChannelType.GuildPublicThread)
7370 ) {
7471 await dropBadge(channel as TextChannel | ThreadChannel, {
7572 ...relic,
76- title: `🏅 ${badgeName}`,
73+ title: `🏅 ${badgeName}`
7774 });
7875 } else {
79- console.warn(`⚠️ Skipping non-text/thread channel: ${chId}`);
76+ console.warn(`⚠️ Skipped invalid channel: ${chId}`);
8077 }
8178 } catch (err) {
82- console.error(`❌ Error dropping badge in ${chId}:`, err);
79+ console.error(`❌ Drop failed in channel ${chId}:`, err);
8380 }
8481 }
8582 });
8683
87- // 4️⃣ Connect to Discord
8884 await discord.login(process.env.DISCORD_TOKEN);
8985})();
0 commit comments