this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore: format

+124 -104
+124 -104
src/index.ts
··· 91 91 // Join all mapped IRC channels on connect 92 92 ircClient.addListener("registered", async () => { 93 93 console.log("Connected to IRC server"); 94 - 94 + 95 95 // Authenticate with NickServ if password is provided 96 96 if (process.env.NICKSERV_PASSWORD && !nickServAuthAttempted) { 97 97 nickServAuthAttempted = true; ··· 114 114 }); 115 115 116 116 // Handle NickServ notices 117 - ircClient.addListener("notice", async (nick: string, to: string, text: string) => { 118 - if (nick !== "NickServ") return; 119 - 120 - console.log(`NickServ: ${text}`); 121 - 122 - // Check for successful authentication 123 - if (text.includes("You are now identified") || text.includes("Password accepted")) { 124 - console.log("✓ Successfully authenticated with NickServ"); 125 - isAuthenticated = true; 126 - 127 - // Join channels after successful auth 128 - const mappings = channelMappings.getAll(); 129 - for (const mapping of mappings) { 130 - ircClient.join(mapping.irc_channel); 117 + ircClient.addListener( 118 + "notice", 119 + async (nick: string, to: string, text: string) => { 120 + if (nick !== "NickServ") return; 121 + 122 + console.log(`NickServ: ${text}`); 123 + 124 + // Check for successful authentication 125 + if ( 126 + text.includes("You are now identified") || 127 + text.includes("Password accepted") 128 + ) { 129 + console.log("✓ Successfully authenticated with NickServ"); 130 + isAuthenticated = true; 131 + 132 + // Join channels after successful auth 133 + const mappings = channelMappings.getAll(); 134 + for (const mapping of mappings) { 135 + ircClient.join(mapping.irc_channel); 136 + } 131 137 } 132 - } 133 - // Check if nick is not registered 134 - else if (text.includes("isn't registered") || text.includes("not registered")) { 135 - console.log("Nick not registered, registering with NickServ..."); 136 - if (process.env.NICKSERV_PASSWORD && process.env.NICKSERV_EMAIL) { 137 - ircClient.say("NickServ", `REGISTER ${process.env.NICKSERV_PASSWORD} ${process.env.NICKSERV_EMAIL}`); 138 - } else { 139 - console.error("Cannot register: NICKSERV_EMAIL not configured"); 138 + // Check if nick is not registered 139 + else if ( 140 + text.includes("isn't registered") || 141 + text.includes("not registered") 142 + ) { 143 + console.log("Nick not registered, registering with NickServ..."); 144 + if (process.env.NICKSERV_PASSWORD && process.env.NICKSERV_EMAIL) { 145 + ircClient.say( 146 + "NickServ", 147 + `REGISTER ${process.env.NICKSERV_PASSWORD} ${process.env.NICKSERV_EMAIL}`, 148 + ); 149 + } else { 150 + console.error("Cannot register: NICKSERV_EMAIL not configured"); 151 + } 140 152 } 141 - } 142 - // Check for failed authentication 143 - else if (text.includes("Invalid password") || text.includes("Access denied")) { 144 - console.error("✗ NickServ authentication failed: Invalid password"); 145 - } 146 - }); 153 + // Check for failed authentication 154 + else if ( 155 + text.includes("Invalid password") || 156 + text.includes("Access denied") 157 + ) { 158 + console.error("✗ NickServ authentication failed: Invalid password"); 159 + } 160 + }, 161 + ); 147 162 148 163 ircClient.addListener( 149 164 "message", ··· 222 237 username: displayName, 223 238 icon_url: iconUrl, 224 239 attachments: attachments, 225 - unfurl_links: false, 226 - unfurl_media: false, 240 + unfurl_links: true, 241 + unfurl_media: true, 227 242 }); 228 243 } else { 229 244 await slackClient.chat.postMessage({ ··· 232 247 text: messageText, 233 248 username: displayName, 234 249 icon_url: iconUrl, 235 - unfurl_links: false, 236 - unfurl_media: false, 250 + unfurl_links: true, 251 + unfurl_media: true, 237 252 }); 238 253 } 239 254 console.log(`IRC → Slack: <${nick}> ${text}`); ··· 248 263 }); 249 264 250 265 // Handle IRC /me actions 251 - ircClient.addListener("action", async (nick: string, to: string, text: string) => { 252 - // Ignore messages from our own bot 253 - const botNickPattern = new RegExp(`^${process.env.IRC_NICK}\\d*$`); 254 - if (botNickPattern.test(nick)) return; 255 - if (nick === "****") return; 266 + ircClient.addListener( 267 + "action", 268 + async (nick: string, to: string, text: string) => { 269 + // Ignore messages from our own bot 270 + const botNickPattern = new RegExp(`^${process.env.IRC_NICK}\\d*$`); 271 + if (botNickPattern.test(nick)) return; 272 + if (nick === "****") return; 256 273 257 - // Find Slack channel mapping for this IRC channel 258 - const mapping = channelMappings.getByIrcChannel(to); 259 - if (!mapping) return; 274 + // Find Slack channel mapping for this IRC channel 275 + const mapping = channelMappings.getByIrcChannel(to); 276 + if (!mapping) return; 260 277 261 - // Check if this IRC nick is mapped to a Slack user 262 - const userMapping = userMappings.getByIrcNick(nick); 278 + // Check if this IRC nick is mapped to a Slack user 279 + const userMapping = userMappings.getByIrcNick(nick); 263 280 264 - let iconUrl: string; 265 - if (userMapping) { 266 - iconUrl = `https://cachet.dunkirk.sh/users/${userMapping.slack_user_id}/r`; 267 - } else { 268 - iconUrl = getAvatarForNick(nick); 269 - } 281 + let iconUrl: string; 282 + if (userMapping) { 283 + iconUrl = `https://cachet.dunkirk.sh/users/${userMapping.slack_user_id}/r`; 284 + } else { 285 + iconUrl = getAvatarForNick(nick); 286 + } 270 287 271 - // Parse IRC formatting and mentions 272 - let messageText = parseIRCFormatting(text); 288 + // Parse IRC formatting and mentions 289 + let messageText = parseIRCFormatting(text); 273 290 274 - // Find all @mentions and nick: mentions in the IRC message 275 - const atMentionPattern = /@(\w+)/g; 276 - const nickMentionPattern = /(\w+):/g; 291 + // Find all @mentions and nick: mentions in the IRC message 292 + const atMentionPattern = /@(\w+)/g; 293 + const nickMentionPattern = /(\w+):/g; 277 294 278 - const atMentions = Array.from(messageText.matchAll(atMentionPattern)); 279 - const nickMentions = Array.from(messageText.matchAll(nickMentionPattern)); 295 + const atMentions = Array.from(messageText.matchAll(atMentionPattern)); 296 + const nickMentions = Array.from(messageText.matchAll(nickMentionPattern)); 280 297 281 - for (const match of atMentions) { 282 - const mentionedNick = match[1] as string; 283 - const mentionedUserMapping = userMappings.getByIrcNick(mentionedNick); 284 - if (mentionedUserMapping) { 285 - messageText = messageText.replace( 286 - match[0], 287 - `<@${mentionedUserMapping.slack_user_id}>`, 288 - ); 298 + for (const match of atMentions) { 299 + const mentionedNick = match[1] as string; 300 + const mentionedUserMapping = userMappings.getByIrcNick(mentionedNick); 301 + if (mentionedUserMapping) { 302 + messageText = messageText.replace( 303 + match[0], 304 + `<@${mentionedUserMapping.slack_user_id}>`, 305 + ); 306 + } 289 307 } 290 - } 291 308 292 - for (const match of nickMentions) { 293 - const mentionedNick = match[1] as string; 294 - const mentionedUserMapping = userMappings.getByIrcNick(mentionedNick); 295 - if (mentionedUserMapping) { 296 - messageText = messageText.replace( 297 - match[0], 298 - `<@${mentionedUserMapping.slack_user_id}>:`, 299 - ); 309 + for (const match of nickMentions) { 310 + const mentionedNick = match[1] as string; 311 + const mentionedUserMapping = userMappings.getByIrcNick(mentionedNick); 312 + if (mentionedUserMapping) { 313 + messageText = messageText.replace( 314 + match[0], 315 + `<@${mentionedUserMapping.slack_user_id}>:`, 316 + ); 317 + } 300 318 } 301 - } 302 319 303 - // Format as action message with context block 304 - const actionText = `${nick} ${messageText}`; 320 + // Format as action message with context block 321 + const actionText = `${nick} ${messageText}`; 305 322 306 - await slackClient.chat.postMessage({ 307 - token: process.env.SLACK_BOT_TOKEN, 308 - channel: mapping.slack_channel_id, 309 - text: actionText, 310 - blocks: [ 311 - { 312 - type: "context", 313 - elements: [ 314 - { 315 - type: "image", 316 - image_url: iconUrl, 317 - alt_text: nick, 318 - }, 319 - { 320 - type: "mrkdwn", 321 - text: actionText, 322 - }, 323 - ], 324 - }, 325 - ], 326 - }); 323 + await slackClient.chat.postMessage({ 324 + token: process.env.SLACK_BOT_TOKEN, 325 + channel: mapping.slack_channel_id, 326 + text: actionText, 327 + blocks: [ 328 + { 329 + type: "context", 330 + elements: [ 331 + { 332 + type: "image", 333 + image_url: iconUrl, 334 + alt_text: nick, 335 + }, 336 + { 337 + type: "mrkdwn", 338 + text: actionText, 339 + }, 340 + ], 341 + }, 342 + ], 343 + }); 327 344 328 - console.log(`IRC → Slack (action): ${actionText}`); 329 - }); 345 + console.log(`IRC → Slack (action): ${actionText}`); 346 + }, 347 + ); 330 348 331 349 // Slack event handlers 332 350 slackApp.event("message", async ({ payload, context }) => { ··· 368 386 const mentions = Array.from(messageText.matchAll(mentionRegex)); 369 387 370 388 for (const match of mentions) { 371 - const userId = match[1]; 372 - const displayName = match[3]; // The name part after | 373 - 389 + const userId = match[1] as string; 390 + const displayName = match[3] as string; // The name part after | 391 + 374 392 // Check if user has a mapped IRC nick 375 393 const mentionedUserMapping = userMappings.getBySlackUser(userId); 376 394 if (mentionedUserMapping) { 377 - messageText = messageText.replace(match[0], `@${mentionedUserMapping.irc_nick}`); 395 + messageText = messageText.replace( 396 + match[0], 397 + `@${mentionedUserMapping.irc_nick}`, 398 + ); 378 399 } else if (displayName) { 379 400 // Use the display name from the mention format <@U123|name> 380 401 messageText = messageText.replace(match[0], `@${displayName}`); ··· 384 405 const response = await fetch( 385 406 `https://cachet.dunkirk.sh/users/${userId}`, 386 407 { 387 - // @ts-ignore - Bun specific option 388 408 tls: { rejectUnauthorized: false }, 389 409 }, 390 410 );