Skip to content

Commit

Permalink
feat: upgrading discordjs to v14
Browse files Browse the repository at this point in the history
  • Loading branch information
SomethingSexy committed Oct 31, 2024
1 parent 535ce9d commit 2dec220
Show file tree
Hide file tree
Showing 16 changed files with 391 additions and 429 deletions.
423 changes: 256 additions & 167 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 4 additions & 6 deletions packages/bot/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
"type": "module",
"scripts": {
"build": "npx swc src -d ./dist",
"deploy:commands": "node --env-file=.env ./dist/framework/discord/deploy-commands.js",
"lint": "eslint ./src --report-unused-disable-directives --max-warnings 0 --no-warn-ignored",
"lint:fix": "eslint ./src --report-unused-disable-directives --max-warnings 0 --no-warn-ignored --fix",
"pretty": "prettier . --ignore-unknown --list-different",
"pretty:fix": "npx prettier . --write --ignore-unknown",
"release": "npx semantic-release",
"start": "cross-env NODE_ENV=production npm run start:core",
"start:core": "node -r dotenv/config ./dist/index.js",
"start": "node --env-file=.env ./dist/index.js",
"test": "exit 0"
},
"husky": {
Expand All @@ -21,7 +21,7 @@
}
},
"nodemonConfig": {
"exec": "cross-env TS_NODE_PROJECT='./tsconfig.dev.json' node -r esm -r ts-node/register/transpile-only -r dotenv/config ./src/server/index.ts",
"exec": "cross-env TS_NODE_PROJECT='./tsconfig.dev.json' node -r esm -r ts-node/register/transpile-only --env-file=.env ./src/server/index.ts",
"ext": "ts tsx",
"ignore": [
"test"
Expand All @@ -37,9 +37,7 @@
"extends": "semantic-release-monorepo"
},
"dependencies": {
"cross-env": "^7.0.2",
"discord.js": "^12.5.1",
"dotenv": "^9.0.2",
"discord.js": "^14.16.3",
"fs-extra": "^10.0.0",
"joi": "^17.4.0",
"neverthrow": "^8.1.1"
Expand Down
11 changes: 0 additions & 11 deletions packages/bot/src/framework/discord/commands/create-character.ts

This file was deleted.

36 changes: 24 additions & 12 deletions packages/bot/src/framework/discord/commands/create-chronicle.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
import { type ChronicleGateway } from '../../../gateway/chronicle/types'
import { type ICommand } from '../types'
import { SlashCommandBuilder } from 'discord.js'
import { chronicleMessage } from '../messages/chronicle.js'
import { createChronicle } from '../../../use-case/create-chronicle.js'

/**
* Handles creating a chronicle (game). This game is tied to the discord server id.
*/
export default {
name: 'create-chronicle',
description: 'Creates a game.',
title: 'Create Chronicle',
execute(
message,
args: [string, 'vtm', 'v5'],
chronicleGateway: ChronicleGateway
) {
command: new SlashCommandBuilder()
.setName('game')
.setDescription('Creates a new game tied to this Discord server.')
.addStringOption((option) =>
option.setName('name').setDescription('Name of game').setRequired(true)
)
.addStringOption((option) =>
option
.setName('type')
.setDescription('Type of game')
.setRequired(true)
.addChoices({ name: 'VtM - v5', value: 'vtm' })
),
execute(interaction, chronicleGateway: ChronicleGateway) {
// Using a TypeGuard here but not sure it should ever get that far?>
// Might be better to make ICommand a generic
if (!interaction.isChatInputCommand()) {
return
}
// For each command, we will pass on the fluture but pipe here error results or success results
// then the caller can just return the result
return createChronicle(chronicleGateway)({
name: args[0],
referenceId: message.guild.id,
name: interaction.options.getString('name', true),
referenceId: interaction.guild.id,
referenceType: 'discord',
game: args[1],
version: args[2],
game: 'vtm',
version: 'v5',
}).map(chronicleMessage)
},
} as ICommand

This file was deleted.

30 changes: 0 additions & 30 deletions packages/bot/src/framework/discord/commands/help.ts

This file was deleted.

12 changes: 1 addition & 11 deletions packages/bot/src/framework/discord/commands/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
// Import all commands here, quick than trying to dynamically load commands with top level await and forcing
// the application to wait to load realtime.
import type { ICommand } from '../types.js'
import createCharacter from './create-character.js'
import createChronicle from './create-chronicle.js'
import createPlayerCharacter from './create-player-character.js'
import help from './help.js'
import roll from './roll.js'

export const all: ICommand[] = [
createCharacter,
createChronicle,
createPlayerCharacter,
help,
roll,
]
export const all: ICommand[] = [createChronicle]
14 changes: 0 additions & 14 deletions packages/bot/src/framework/discord/commands/roll.ts

This file was deleted.

17 changes: 0 additions & 17 deletions packages/bot/src/framework/discord/commands/update-character.ts

This file was deleted.

16 changes: 4 additions & 12 deletions packages/bot/src/framework/discord/configurations.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
// import fs from 'fs';
import Discord from 'discord.js'
import type { ICommand } from './types'
import { Collection } from 'discord.js'
import { type ICommand } from './types'
import { all } from './commands/index.js'
// import { endsWith } from '../../utils/string.js';
// import { dirname } from 'path';
// import { fileURLToPath } from 'url';

// const __dirname = dirname(fileURLToPath(import.meta.url));
// const endsWithJs = endsWith('.js');
// const commandFiles = fs.readdirSync(`${__dirname}/commands`).filter(endsWithJs);
// const rawCommands = await Promise.all(commandFiles.map(async (file) => import(`${__dirname}/commands/${file}`) as Promise<ICommand>));
const discordCommands = new Collection<string, ICommand>()

const discordCommands = new Discord.Collection<string, ICommand>()
all.forEach((command) => {
discordCommands.set(command.name, command)
discordCommands.set(command.command.name, command)
})

/**
Expand Down
27 changes: 27 additions & 0 deletions packages/bot/src/framework/discord/deploy-commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { REST, Routes } from 'discord.js'
import { commands } from './configurations.js'

const { DISCORD_TOKEN, DISCORD_CLIENT_ID, DISCORD_GUILD_ID } = process.env

const rest = new REST().setToken(DISCORD_TOKEN)

const slashCommands = commands.map((command) => command.command.toJSON())

;(async () => {
try {
console.log(`Started refreshing ${commands.size} application (/) commands.`)

// The put method is used to fully refresh all commands in the guild with the current set
const data = (await rest.put(
Routes.applicationGuildCommands(DISCORD_CLIENT_ID, DISCORD_GUILD_ID),
{ body: slashCommands }
)) as Array<unknown>

console.log(
`Successfully reloaded ${data.length} application (/) commands.`
)
} catch (error) {
// And of course, make sure you catch and log any errors!
console.error(error)
}
})()
84 changes: 45 additions & 39 deletions packages/bot/src/framework/discord/index.ts
Original file line number Diff line number Diff line change
@@ -1,74 +1,80 @@
import { Client, Events, GatewayIntentBits, type Interaction } from 'discord.js'
import { type CommandResult, type Result } from './types'
import Discord from 'discord.js'
import { chronicleGateway } from '../../gateway/chronicle/rest/index.js'
import { commands } from './configurations.js'
import { isString } from '../../utils/string.js'
import { rest } from '../../service/rest/node.js'

const prefix = '!'

const sendResult = (message: Discord.Message) => (result: Result) => {
if (isString(result)) {
message.reply(result)
} else {
message.channel.send(result)
const sendResult = (interaction: Interaction) => (result: Result) => {
if (interaction.isChatInputCommand()) {
if (isString(result)) {
interaction.reply(result)
} else {
interaction.channel.send(result)
}
}
}

const handleResult = (message: Discord.Message) => (result: CommandResult) => {
const sendMessageResult = sendResult(message)
const handleResult = (interaction: Interaction) => (result: CommandResult) => {
const sendMessageResult = sendResult(interaction)
result.map(sendMessageResult).mapErr(sendMessageResult)
}

// Initialize Discord Bot
const client = new Discord.Client()
const client = new Client({ intents: [GatewayIntentBits.Guilds] })

client.on('ready', () => {
client.once(Events.ClientReady, () => {
console.log(`Logged in as ${client.user.tag}!`)
})

client.on('message', (message) => {
console.log(
`Accepting command ${message.content} from user ${message.author.username}:${message.author.id} from server ${message.guild.name}:${message.guild.id}`
)
if (!message.content.startsWith(prefix) || message.author.bot) {
client.on(Events.InteractionCreate, (interaction) => {
if (!interaction.isChatInputCommand()) {
return
}

const args = message.content.slice(prefix.length).trim().split(/ +/)
const commandName = args.shift().toLowerCase()
console.log(
`Accepting command ${interaction.commandName} from user ${interaction.member.user.username}:${interaction.member.user.id} from server ${interaction.guild.name}:${interaction.guild.id}`
)
const command = commands.get(interaction.commandName)

// if (!message.content.startsWith(prefix) || message.author.bot) {
// return
// }

// const args = message.content.slice(prefix.length).trim().split(/ +/)
// const commandName = args.shift().toLowerCase()

const command =
commands.get(commandName) ||
commands.find((cmd) => cmd.aliases && cmd.aliases.includes(commandName))
// const command =
// commands.get(commandName) ||
// commands.find((cmd) => cmd.aliases && cmd.aliases.includes(commandName))

if (!command) {
return
}

if (command.guildOnly && message.channel.type === 'dm') {
return message.reply("I can't execute that command inside DMs!")
}
// if (command.guildOnly && message.channel.type === 'dm') {
// return message.reply("I can't execute that command inside DMs!")
// }

if (command.args && !args.length) {
if (command.usage) {
return message.channel.send(`
You didn't provide any arguments, ${message.author}!
The proper usage would be: \`${prefix}${command.name} ${command.usage}
`)
}
// if (command.args && !args.length) {
// if (command.usage) {
// return message.channel.send(`
// You didn't provide any arguments, ${message.author}!
// The proper usage would be: \`${prefix}${command.name} ${command.usage}
// `)
// }

return message.channel.send(
`You didn't provide any arguments, ${message.author}!`
)
}
// return message.channel.send(
// `You didn't provide any arguments, ${message.author}!`
// )
// }

try {
// TODO: As we add more gateways we will want to figure out a better way to pass these in
const result = command.execute(message, args, chronicleGateway(rest))
handleResult(message)(result)
const result = command.execute(interaction, chronicleGateway(rest))
handleResult(interaction)(result)
} catch (error) {
message.reply(
interaction.reply(
`There was an error trying to execute that command! - ${error}`
)
}
Expand Down
Loading

0 comments on commit 2dec220

Please sign in to comment.