feat: initial prototype
All checks were successful
Node.js CI / Lint and Test (push) Successful in 31s

This commit is contained in:
2025-02-25 16:37:00 -08:00
parent 2ba0ae631b
commit f3ab9e541f
12 changed files with 4978 additions and 0 deletions

24
src/config/channels.ts Normal file
View File

@ -0,0 +1,24 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
/**
* The channels to post standup reminders in.
*/
export const channels = [
"1326291362483671202",
"1329625299406684263",
"1326291172896931921",
"1326291132535013409",
"1326291241045856286",
"1326291186863833169",
"1326291226332496026",
"1326291379621597304",
"1326291254421749770",
"1326291160632655983",
"1326291146267430912",
"1326291198666866788",
"1326291214026408009",
];

38
src/index.ts Normal file
View File

@ -0,0 +1,38 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Client, Events, GatewayIntentBits } from "discord.js";
import { scheduleJob } from "node-schedule";
import { standup } from "./modules/standup.js";
import { logger } from "./utils/logger.js";
process.on("unhandledRejection", (error) => {
if (error instanceof Error) {
void logger.error("Unhandled Rejection", error);
return;
}
void logger.error("unhandled rejection", new Error(String(error)));
});
process.on("uncaughtException", (error) => {
if (error instanceof Error) {
void logger.error("Uncaught Exception", error);
return;
}
void logger.error("uncaught exception", new Error(String(error)));
});
const client = new Client({
intents: [ GatewayIntentBits.Guilds ],
});
client.on(Events.ClientReady, () => {
void logger.log("debug", "Bot is ready.");
scheduleJob("reminders", "0 6 * * 1-5", async() => {
await standup(client);
});
});
await client.login(process.env.DISCORD_TOKEN);

48
src/modules/standup.ts Normal file
View File

@ -0,0 +1,48 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { channels } from "../config/channels.js";
import { logger } from "../utils/logger.js";
import type { Client } from "discord.js";
/**
* Posts a daily standup reminder in configured channels.
* @param client - The Discord client.
*/
export const standup = async(client: Client): Promise<void> => {
try {
const mapped = await Promise.all(
channels.map(async(channel) => {
const fetched = await client.channels.fetch(channel).catch(() => {
return null;
});
if (!fetched) {
return null;
}
if (!fetched.isTextBased() || !("send" in fetched)) {
return null;
}
return fetched;
}),
);
const filtered = mapped.filter((channel) => {
return channel !== null;
});
await Promise.all(
filtered.map(async(channel) => {
await channel.send(
// eslint-disable-next-line stylistic/max-len -- This message is too long to fit on one line.
"Good morning @everyone~! It's time for standup! Please share your goals for today.",
);
}),
);
} catch (error) {
if (error instanceof Error) {
await logger.error("standup module", error);
return;
}
await logger.error("standup module", new Error(String(error)));
}
};

12
src/utils/logger.ts Normal file
View File

@ -0,0 +1,12 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Logger } from "@nhcarrigan/logger";
export const logger = new Logger(
"Standup Bot",
process.env.LOG_TOKEN ?? "",
);