generated from nhcarrigan/template
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 10c7d337a5 | |||
| 60fec0f2d8 | |||
| 0a3c000add | |||
| 0394d03361 |
+1
-1
@@ -17,7 +17,7 @@
|
||||
"devDependencies": {
|
||||
"@nhcarrigan/eslint-config": "5.2.0",
|
||||
"@nhcarrigan/typescript-config": "4.0.0",
|
||||
"@types/node": "25.2.3",
|
||||
"@types/node": "24.3.0",
|
||||
"@types/node-schedule": "2.1.8",
|
||||
"eslint": "9.33.0",
|
||||
"typescript": "5.9.2"
|
||||
|
||||
Generated
+28
-28
@@ -35,13 +35,13 @@ importers:
|
||||
devDependencies:
|
||||
'@nhcarrigan/eslint-config':
|
||||
specifier: 5.2.0
|
||||
version: 5.2.0(@typescript-eslint/utils@8.40.0(eslint@9.33.0)(typescript@5.9.2))(eslint@9.33.0)(playwright@1.54.2)(react@19.1.1)(typescript@5.9.2)(vitest@3.2.4(@types/node@25.2.3))
|
||||
version: 5.2.0(@typescript-eslint/utils@8.40.0(eslint@9.33.0)(typescript@5.9.2))(eslint@9.33.0)(playwright@1.54.2)(react@19.1.1)(typescript@5.9.2)(vitest@3.2.4(@types/node@24.3.0))
|
||||
'@nhcarrigan/typescript-config':
|
||||
specifier: 4.0.0
|
||||
version: 4.0.0(typescript@5.9.2)
|
||||
'@types/node':
|
||||
specifier: 25.2.3
|
||||
version: 25.2.3
|
||||
specifier: 24.3.0
|
||||
version: 24.3.0
|
||||
'@types/node-schedule':
|
||||
specifier: 2.1.8
|
||||
version: 2.1.8
|
||||
@@ -646,8 +646,8 @@ packages:
|
||||
'@types/node-schedule@2.1.8':
|
||||
resolution: {integrity: sha512-k00g6Yj/oUg/CDC+MeLHUzu0+OFxWbIqrFfDiLi6OPKxTujvpv29mHGM8GtKr7B+9Vv92FcK/8mRqi1DK5f3hA==}
|
||||
|
||||
'@types/node@25.2.3':
|
||||
resolution: {integrity: sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==}
|
||||
'@types/node@24.3.0':
|
||||
resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==}
|
||||
|
||||
'@types/normalize-package-data@2.4.4':
|
||||
resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
|
||||
@@ -2238,8 +2238,8 @@ packages:
|
||||
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
undici-types@7.16.0:
|
||||
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||
undici-types@7.10.0:
|
||||
resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==}
|
||||
|
||||
undici@6.21.3:
|
||||
resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==}
|
||||
@@ -2645,7 +2645,7 @@ snapshots:
|
||||
discord.js: 14.22.0
|
||||
node-schedule: 2.1.1
|
||||
|
||||
'@nhcarrigan/eslint-config@5.2.0(@typescript-eslint/utils@8.40.0(eslint@9.33.0)(typescript@5.9.2))(eslint@9.33.0)(playwright@1.54.2)(react@19.1.1)(typescript@5.9.2)(vitest@3.2.4(@types/node@25.2.3))':
|
||||
'@nhcarrigan/eslint-config@5.2.0(@typescript-eslint/utils@8.40.0(eslint@9.33.0)(typescript@5.9.2))(eslint@9.33.0)(playwright@1.54.2)(react@19.1.1)(typescript@5.9.2)(vitest@3.2.4(@types/node@24.3.0))':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-plugin-eslint-comments': 4.4.1(eslint@9.33.0)
|
||||
'@eslint/compat': 1.2.4(eslint@9.33.0)
|
||||
@@ -2654,7 +2654,7 @@ snapshots:
|
||||
'@stylistic/eslint-plugin': 2.12.1(eslint@9.33.0)(typescript@5.9.2)
|
||||
'@typescript-eslint/eslint-plugin': 8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.33.0)(typescript@5.9.2))(eslint@9.33.0)(typescript@5.9.2)
|
||||
'@typescript-eslint/parser': 8.19.0(eslint@9.33.0)(typescript@5.9.2)
|
||||
'@vitest/eslint-plugin': 1.1.24(@typescript-eslint/utils@8.40.0(eslint@9.33.0)(typescript@5.9.2))(eslint@9.33.0)(typescript@5.9.2)(vitest@3.2.4(@types/node@25.2.3))
|
||||
'@vitest/eslint-plugin': 1.1.24(@typescript-eslint/utils@8.40.0(eslint@9.33.0)(typescript@5.9.2))(eslint@9.33.0)(typescript@5.9.2)(vitest@3.2.4(@types/node@24.3.0))
|
||||
eslint: 9.33.0
|
||||
eslint-plugin-deprecation: 3.0.0(eslint@9.33.0)(typescript@5.9.2)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.19.0(eslint@9.33.0)(typescript@5.9.2))(eslint@9.33.0)
|
||||
@@ -2667,7 +2667,7 @@ snapshots:
|
||||
playwright: 1.54.2
|
||||
react: 19.1.1
|
||||
typescript: 5.9.2
|
||||
vitest: 3.2.4(@types/node@25.2.3)
|
||||
vitest: 3.2.4(@types/node@24.3.0)
|
||||
transitivePeerDependencies:
|
||||
- '@typescript-eslint/utils'
|
||||
- eslint-import-resolver-typescript
|
||||
@@ -2942,17 +2942,17 @@ snapshots:
|
||||
|
||||
'@types/node-schedule@2.1.8':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 24.3.0
|
||||
|
||||
'@types/node@25.2.3':
|
||||
'@types/node@24.3.0':
|
||||
dependencies:
|
||||
undici-types: 7.16.0
|
||||
undici-types: 7.10.0
|
||||
|
||||
'@types/normalize-package-data@2.4.4': {}
|
||||
|
||||
'@types/ws@8.18.1':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 24.3.0
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.33.0)(typescript@5.9.2))(eslint@9.33.0)(typescript@5.9.2)':
|
||||
dependencies:
|
||||
@@ -3121,13 +3121,13 @@ snapshots:
|
||||
'@typescript-eslint/types': 8.40.0
|
||||
eslint-visitor-keys: 4.2.1
|
||||
|
||||
'@vitest/eslint-plugin@1.1.24(@typescript-eslint/utils@8.40.0(eslint@9.33.0)(typescript@5.9.2))(eslint@9.33.0)(typescript@5.9.2)(vitest@3.2.4(@types/node@25.2.3))':
|
||||
'@vitest/eslint-plugin@1.1.24(@typescript-eslint/utils@8.40.0(eslint@9.33.0)(typescript@5.9.2))(eslint@9.33.0)(typescript@5.9.2)(vitest@3.2.4(@types/node@24.3.0))':
|
||||
dependencies:
|
||||
'@typescript-eslint/utils': 8.40.0(eslint@9.33.0)(typescript@5.9.2)
|
||||
eslint: 9.33.0
|
||||
optionalDependencies:
|
||||
typescript: 5.9.2
|
||||
vitest: 3.2.4(@types/node@25.2.3)
|
||||
vitest: 3.2.4(@types/node@24.3.0)
|
||||
|
||||
'@vitest/expect@3.2.4':
|
||||
dependencies:
|
||||
@@ -3137,13 +3137,13 @@ snapshots:
|
||||
chai: 5.3.1
|
||||
tinyrainbow: 2.0.0
|
||||
|
||||
'@vitest/mocker@3.2.4(vite@7.1.3(@types/node@25.2.3))':
|
||||
'@vitest/mocker@3.2.4(vite@7.1.3(@types/node@24.3.0))':
|
||||
dependencies:
|
||||
'@vitest/spy': 3.2.4
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.17
|
||||
optionalDependencies:
|
||||
vite: 7.1.3(@types/node@25.2.3)
|
||||
vite: 7.1.3(@types/node@24.3.0)
|
||||
|
||||
'@vitest/pretty-format@3.2.4':
|
||||
dependencies:
|
||||
@@ -4884,7 +4884,7 @@ snapshots:
|
||||
has-symbols: 1.1.0
|
||||
which-boxed-primitive: 1.1.1
|
||||
|
||||
undici-types@7.16.0: {}
|
||||
undici-types@7.10.0: {}
|
||||
|
||||
undici@6.21.3: {}
|
||||
|
||||
@@ -4907,13 +4907,13 @@ snapshots:
|
||||
spdx-correct: 3.2.0
|
||||
spdx-expression-parse: 3.0.1
|
||||
|
||||
vite-node@3.2.4(@types/node@25.2.3):
|
||||
vite-node@3.2.4(@types/node@24.3.0):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.4.1
|
||||
es-module-lexer: 1.7.0
|
||||
pathe: 2.0.3
|
||||
vite: 7.1.3(@types/node@25.2.3)
|
||||
vite: 7.1.3(@types/node@24.3.0)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- jiti
|
||||
@@ -4928,7 +4928,7 @@ snapshots:
|
||||
- tsx
|
||||
- yaml
|
||||
|
||||
vite@7.1.3(@types/node@25.2.3):
|
||||
vite@7.1.3(@types/node@24.3.0):
|
||||
dependencies:
|
||||
esbuild: 0.25.9
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
@@ -4937,14 +4937,14 @@ snapshots:
|
||||
rollup: 4.46.3
|
||||
tinyglobby: 0.2.14
|
||||
optionalDependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 24.3.0
|
||||
fsevents: 2.3.3
|
||||
|
||||
vitest@3.2.4(@types/node@25.2.3):
|
||||
vitest@3.2.4(@types/node@24.3.0):
|
||||
dependencies:
|
||||
'@types/chai': 5.2.2
|
||||
'@vitest/expect': 3.2.4
|
||||
'@vitest/mocker': 3.2.4(vite@7.1.3(@types/node@25.2.3))
|
||||
'@vitest/mocker': 3.2.4(vite@7.1.3(@types/node@24.3.0))
|
||||
'@vitest/pretty-format': 3.2.4
|
||||
'@vitest/runner': 3.2.4
|
||||
'@vitest/snapshot': 3.2.4
|
||||
@@ -4962,11 +4962,11 @@ snapshots:
|
||||
tinyglobby: 0.2.14
|
||||
tinypool: 1.1.1
|
||||
tinyrainbow: 2.0.0
|
||||
vite: 7.1.3(@types/node@25.2.3)
|
||||
vite-node: 3.2.4(@types/node@25.2.3)
|
||||
vite: 7.1.3(@types/node@24.3.0)
|
||||
vite-node: 3.2.4(@types/node@24.3.0)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 24.3.0
|
||||
transitivePeerDependencies:
|
||||
- jiti
|
||||
- less
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @copyright NHCarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Teklu Abayneh
|
||||
*/
|
||||
|
||||
import {
|
||||
ContextMenuCommandBuilder,
|
||||
ApplicationCommandType,
|
||||
type MessageContextMenuCommandInteraction,
|
||||
DiscordAPIError,
|
||||
ButtonBuilder,
|
||||
EmbedBuilder,
|
||||
ActionRowBuilder,
|
||||
ButtonStyle,
|
||||
type Message,
|
||||
} from "discord.js";
|
||||
import { ids } from "../config/ids.js";
|
||||
|
||||
const buildForwardedEmbed = (message: Message): EmbedBuilder => {
|
||||
const forwardedEmbed = new EmbedBuilder().
|
||||
setColor(0x58_65_F2).
|
||||
setTitle(`Message from ${String(message.author.tag)}!`).
|
||||
setDescription(
|
||||
`${(message.attachments.size > 0
|
||||
? `**Attachments:** ${String(message.attachments.size)}
|
||||
file(s)\n\n`
|
||||
: "\n")
|
||||
+ (message.embeds.length > 0
|
||||
? `**Embeds:** ${String(message.embeds.length)}\n\n`
|
||||
: "")}
|
||||
\n${message.content}\n\n`,
|
||||
);
|
||||
return forwardedEmbed;
|
||||
};
|
||||
const buildViewButtonFunction = (message: Message): ButtonBuilder => {
|
||||
const viewButton = new ButtonBuilder().
|
||||
setLabel("View Message").
|
||||
setURL(message.url).
|
||||
setStyle(ButtonStyle.Link);
|
||||
return viewButton;
|
||||
};
|
||||
|
||||
const data = new ContextMenuCommandBuilder().setName("Forward to Naomi").
|
||||
setType(ApplicationCommandType.Message);
|
||||
|
||||
const execute = async(interaction: MessageContextMenuCommandInteraction):
|
||||
Promise<void> => {
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
|
||||
if (interaction.user.id !== ids.users.naomi) {
|
||||
await interaction.editReply("❌ Only Naomi can use this command.");
|
||||
return;
|
||||
}
|
||||
|
||||
const message = interaction.targetMessage;
|
||||
if (message.author.id === ids.users.naomi) {
|
||||
await interaction.editReply(
|
||||
"No need to forward your own message to yourself 😄",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const naomi = await interaction.client.users.fetch(ids.users.naomi);
|
||||
const forwardedEmbed = buildForwardedEmbed(message);
|
||||
const viewButton = buildViewButtonFunction(message);
|
||||
|
||||
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
viewButton,
|
||||
);
|
||||
await naomi.send({
|
||||
components: [ row ],
|
||||
embeds: [ forwardedEmbed ],
|
||||
files: message.attachments.map((att) => {
|
||||
return att.url;
|
||||
}),
|
||||
});
|
||||
|
||||
await interaction.editReply({
|
||||
content: "✅ Forwarded to your DMs!",
|
||||
});
|
||||
} catch (error) {
|
||||
let replyText = "❌ Failed to forward message.";
|
||||
if (error instanceof DiscordAPIError && error.code === 50_007) {
|
||||
replyText = `${replyText} (Naomi's DMs might be closed)`;
|
||||
}
|
||||
await interaction.editReply(replyText);
|
||||
}
|
||||
};
|
||||
|
||||
export const forwardOwnerDM = {
|
||||
data,
|
||||
execute,
|
||||
};
|
||||
@@ -70,5 +70,6 @@ export const ids = {
|
||||
amari: "1406431359345496255",
|
||||
naomi: "465650873650118659",
|
||||
nhcarrigan: "1382837581649150104",
|
||||
teklu: "1381735115163570198",
|
||||
},
|
||||
};
|
||||
|
||||
+31
-10
@@ -14,6 +14,7 @@ import {
|
||||
} from "discord.js";
|
||||
import { scheduleJob } from "node-schedule";
|
||||
import { App } from "octokit";
|
||||
import { forwardOwnerDM } from "./commands/forwardToOwner.js";
|
||||
import { ids } from "./config/ids.js";
|
||||
import { handleMessageCreate } from "./events/handleMessageCreate.js";
|
||||
import { cacheData } from "./modules/cacheData.js";
|
||||
@@ -41,6 +42,7 @@ const githubApp = new App({
|
||||
appId: process.env.GH_CLIENT_ID,
|
||||
privateKey: process.env.GH_PRIVATE_KEY.replaceAll("\\n", "\n"),
|
||||
});
|
||||
|
||||
const octokit = await githubApp.getInstallationOctokit(83_119_105);
|
||||
const { data } = await octokit.rest.apps.getAuthenticated();
|
||||
await logger.log(
|
||||
@@ -87,12 +89,18 @@ amari.discord.once(Events.ClientReady, () => {
|
||||
scheduleJob("post progress reminders", "0 9 * * 1-5", async() => {
|
||||
await postProgressReminders(amari);
|
||||
});
|
||||
setInterval(() => {
|
||||
amari.recentlyActiveChannels = new Set<string>();
|
||||
}, 10 * 60 * 1000);
|
||||
setInterval(() => {
|
||||
void checkRetroAchievements(amari);
|
||||
}, 10 * 60 * 1000);
|
||||
setInterval(
|
||||
() => {
|
||||
amari.recentlyActiveChannels = new Set<string>();
|
||||
},
|
||||
10 * 60 * 1000,
|
||||
);
|
||||
setInterval(
|
||||
() => {
|
||||
void checkRetroAchievements(amari);
|
||||
},
|
||||
10 * 60 * 1000,
|
||||
);
|
||||
});
|
||||
|
||||
amari.discord.on(Events.MessageCreate, (message) => {
|
||||
@@ -105,19 +113,32 @@ amari.discord.on(Events.MessageCreate, (message) => {
|
||||
|
||||
amari.discord.on(Events.InteractionCreate, (interaction) => {
|
||||
void analytics.logGatewayEvent(Events.InteractionCreate, { ...interaction });
|
||||
|
||||
if (
|
||||
interaction.isMessageContextMenuCommand()
|
||||
&& interaction.commandName === "Forward to Naomi"
|
||||
) {
|
||||
void forwardOwnerDM.execute(interaction);
|
||||
return;
|
||||
}
|
||||
|
||||
if (interaction.isButton() && interaction.customId === "resolve") {
|
||||
if (interaction.user.id !== ids.users.naomi) {
|
||||
return void interaction.reply({
|
||||
void interaction.reply({
|
||||
content: "Who are you????",
|
||||
flags: [ MessageFlags.Ephemeral ],
|
||||
});
|
||||
return;
|
||||
}
|
||||
return void interaction.message.delete();
|
||||
|
||||
void interaction.message.delete();
|
||||
return;
|
||||
}
|
||||
if (interaction.isAutocomplete()) {
|
||||
return void interaction;
|
||||
void interaction;
|
||||
return;
|
||||
}
|
||||
return void interaction.reply({
|
||||
void interaction.reply({
|
||||
content: "What?",
|
||||
flags: [ MessageFlags.Ephemeral ],
|
||||
});
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @copyright NHCarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Teklu Abayneh
|
||||
*/
|
||||
|
||||
import { REST, Routes } from "discord.js";
|
||||
import { forwardOwnerDM } from "../commands/forwardToOwner.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
|
||||
const commands = [ forwardOwnerDM.data.toJSON() ];
|
||||
const token = process.env.BOT_TOKEN;
|
||||
const clientId = process.env.GH_CLIENT_ID;
|
||||
|
||||
if (token === undefined) {
|
||||
throw new Error("BOT_TOKEN is missing from environment variables!");
|
||||
}
|
||||
if (clientId === undefined) {
|
||||
throw new Error("CLIENT_ID is missing from environment variables!");
|
||||
}
|
||||
|
||||
const rest = new REST({ version: "10" }).setToken(token);
|
||||
const requestCommand = async(): Promise<void> => {
|
||||
try {
|
||||
await rest.put(Routes.applicationCommands(clientId), { body: commands });
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
await logger.error("operation", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
void requestCommand();
|
||||
Reference in New Issue
Block a user