this repo has no description
1import { SlackApp } from "slack-edge";
2import { version } from "./package.json";
3import * as irc from "irc-framework";
4
5const missingEnvVars = [];
6if (!process.env.SLACK_BOT_TOKEN) missingEnvVars.push("SLACK_BOT_TOKEN");
7if (!process.env.SLACK_SIGNING_SECRET) missingEnvVars.push("SLACK_SIGNING_SECRET");
8if (!process.env.ADMINS) missingEnvVars.push("ADMINS");
9if (!process.env.IRC_NICK) missingEnvVars.push("IRC_NICK");
10if (!process.env.IRC_CHANNEL) missingEnvVars.push("IRC_CHANNEL");
11
12if (missingEnvVars.length > 0) {
13 throw new Error(
14 `Missing required environment variables: ${missingEnvVars.join(", ")}`,
15 );
16}
17
18const slackApp = new SlackApp({
19 env: {
20 SLACK_BOT_TOKEN: process.env.SLACK_BOT_TOKEN,
21 SLACK_SIGNING_SECRET: process.env.SLACK_SIGNING_SECRET,
22 SLACK_LOGGING_LEVEL: "INFO",
23 },
24 startLazyListenerAfterAck: true,
25});
26const slackClient = slackApp.client;
27
28// IRC client setup
29const ircClient = new irc.Client();
30ircClient.connect({
31 host: "irc.hackclub.com",
32 port: 6667,
33 tls: false,
34 nick: process.env.IRC_NICK,
35 username: process.env.IRC_NICK,
36 gecos: "Slack IRC Bridge",
37 auto_reconnect: true,
38 auto_reconnect_wait: 4000,
39 auto_reconnect_max_retries: 0,
40});
41
42const ircChannel = process.env.IRC_CHANNEL;
43const slackChannel = process.env.SLACK_CHANNEL;
44
45// IRC event handlers
46ircClient.on("registered", () => {
47 console.log("Connected to IRC server");
48 ircClient.join(ircChannel);
49});
50
51ircClient.on("join", (event) => {
52 if (event.nick === ircClient.user.nick) {
53 console.log(`Joined IRC channel: ${event.channel}`);
54 }
55});
56
57ircClient.on("message", async (event) => {
58 if (event.nick === ircClient.user.nick) return;
59 if (event.nick === "****") return;
60
61 if (slackChannel) {
62 try {
63 await slackClient.chat.postMessage({
64 token: process.env.SLACK_BOT_TOKEN,
65 channel: slackChannel,
66 text: event.message,
67 username: event.nick,
68 unfurl_links: false,
69 unfurl_media: false,
70 });
71 } catch (error) {
72 console.error("Error posting to Slack:", error);
73 }
74 }
75});
76
77ircClient.on("close", () => {
78 console.log("Disconnected from IRC server");
79});
80
81ircClient.on("error", (error) => {
82 console.error("IRC error:", error);
83});
84
85// Slack event handlers
86slackApp.event("message", async ({ payload }) => {
87 if (payload.subtype) return;
88 if (payload.bot_id) return;
89 if (!slackChannel || payload.channel !== slackChannel) return;
90
91 try {
92 const userInfo = await slackClient.users.info({
93 token: process.env.SLACK_BOT_TOKEN,
94 user: payload.user,
95 });
96
97 const username = userInfo.user?.real_name || userInfo.user?.name || "Unknown";
98 const message = `<${username}> ${payload.text}`;
99
100 ircClient.say(ircChannel, message);
101 } catch (error) {
102 console.error("Error handling Slack message:", error);
103 }
104});
105
106export default {
107 port: process.env.PORT || 3000,
108 async fetch(request: Request) {
109 const url = new URL(request.url);
110 const path = url.pathname;
111
112 switch (path) {
113 case "/":
114 return new Response(`Hello World from irc-slack-bridge@${version}`);
115 case "/health":
116 return new Response("OK");
117 case "/slack":
118 return slackApp.run(request);
119 default:
120 return new Response("404 Not Found", { status: 404 });
121 }
122 },
123};
124
125console.log(
126 `🚀 Server Started in ${Bun.nanoseconds() / 1000000} milliseconds on version: ${version}!\n\n----------------------------------\n`,
127);
128console.log(`Connecting to IRC: irc.hackclub.com:6667 as ${process.env.IRC_NICK}`);
129console.log(`IRC Channel: ${ircChannel}`);
130console.log(`Slack Channel: ${slackChannel || "Not configured (IRC->Slack only)"}`);
131
132export { slackApp, slackClient, ircClient, version };
133