Closed Ognisty321 closed 3 months ago
Hi! In v0.7.2 I did not provide an embed builder because embed is a pure object. I added it in v0.7.3 to try it out. I also created a simple Docs.
Thanks for adding embed support in v0.7.3! The new docs are really helpful.
I picked Discord Hono for my project because it's fast and works with Cloudflare Workers. I like that it's serverless.
I've used Discord.js before, and I'm wondering how much of what it can do, Discord Hono can do too. Do you think Discord Hono will eventually do everything Discord.js can? Also, are you thinking about using similar names for things as Discord.js does? That might make it easier for people to switch over.
I'm trying to figure out how to make a weather command in Discord Hono. In my Discord.js bot, I had a command that did these things:
How could I create something similar using the current version of Discord Hono? Are there any limitations I should be aware of when trying to implement this kind of interactive command with multiple API calls and dynamic updates?
Thank you for choosing Discord Hono!
Regarding Discord.js, I have never used Discord.js, so I am including speculation, but I made this comparison. https://discord-hono.luis.fun/overview/features/#server-based-bot-vs-serverless-bot Also, as you can see from this comparison, I cannot reproduce all the features of Discord.js (server-based bot).
As for keeping the usability the same as Discord.js, I am not currently considering adapting the way the Discord Hono code is written to Discord.js. However, it may be very useful to provide a guide for switching from Discord.js to Discord Hono. (I would need to be somewhat familiar with Discord.js, though.)
I have created a sample code for the Weather Bot you are trying to create. Please take a look at it for reference.
// index.ts
import { Button, Components, DiscordHono, Embed } from 'discord-hono'
type Env = {
Variables: {
city?: string
}
}
const deleteButton = new Button('message-delete', 'Delete', 'Secondary').emoji({ name: '🗑️' })
const app = new DiscordHono<Env>()
.command('weather', c => {
const city = c.var.city || 'default city'
const fetchWeatherInfo = `Weather: ${city}`
const embed = new Embed().title('Weather Info').description(fetchWeatherInfo)
const components = new Components().row(
new Button('alert', 'Weather Alerts').custom_id(city).emoji({ name: '⚠️' }),
deleteButton,
)
return c.res({ embeds: [embed], components })
})
.component('alert', c => {
const city = c.interaction.data?.custom_id || 'default city'
const fetchAlertInfo = `Alerts: ${city}`
const embed = new Embed().title('Alerts Info').description(fetchAlertInfo)
const components = new Components().row(deleteButton)
return c.resUpdate({ embeds: [embed], components })
})
.component('message-delete', c => c.resDeferUpdate(c.followupDelete))
export default app
// register.ts
import { Command, Option, register } from 'discord-hono'
const commands = [
new Command('weather', 'weather info').options(new Option('city', 'city name').required()),
]
One limitation to note is that the 'alert' and custom_id city strings in the sample code are limited to a combined total of 99 characters. Also, unlike Discord.js server-based bots, the previous state cannot be saved. (I think you can use cloudflare kv or cloudflare d1 ingeniously as a substitute.) Therefore, the previous state is saved in custom_id, etc., and it is referred to when operating buttons, etc.
Thanks for the detailed reply and that sample code as it's very helpful.
I totally forgot to mention earlier that in my Discord.js bot, I was using ephemeral messages to control if the users want to show it for everyone or not. And I had a feature where users could click buttons under the embed to flip through pages - because showing weather for each hour over 24 hours would be way too much for one embed.
Your sample code is great - gives me a solid starting point. I can see how to handle the basic weather command and show alerts with buttons. Pretty clever using custom_id for the city info, considering how serverless functions work.
I'm kinda curious about a few things:
For longer content like hourly forecasts, how could I implement page switching using buttons in Discord Hono? Is there a way to update the embed content when a user clicks a "next page" or "previous page" button?
I read in your repo that Discord Hono is heavily influenced by Hono, and I noticed that they mention Bun and Deno in their docs. Have you considered switching to Bun as the primary runtime? I've heard it's supposed to be 377% faster than regular Node. Could this speed boost benefit Discord Hono users?
Thanks again for explaining everything and for the sample code. It's really helping me figure out how to move my project over to Discord Hono.
Glad my reply could help you.
I made a sample code that implements ephemeral messages and page switching. Please take a look at it for reference.
// index.ts
import { Button, Components, DiscordHono, Embed } from 'discord-hono'
type Env = {
Variables: {
city?: string
public?: boolean
}
}
const deleteButton = new Button('message-delete', 'Delete', 'Secondary').emoji({ name: '🗑️' })
const weatherInfo = (city: string, nowPage: number) => {
const maxPage = 3
const fetchWeatherInfo = `Weather: ${city} \nPage: ${nowPage}`
const fetchAlertInfo = `Alerts: ${city}`
const noAlert = fetchAlertInfo ? true : false
const previousPageId = JSON.stringify([city, nowPage - 1])
const nextPageId = JSON.stringify([city, nowPage + 1])
// Might need to check character limit check.
const embed = new Embed().title('Weather Info').description(fetchWeatherInfo)
const components = new Components()
.row(
new Button('weather', 'Previous')
.custom_id(previousPageId)
.emoji({ name: '⬅️' })
.disabled(nowPage <= 1),
new Button('weather', 'Next')
.custom_id(nextPageId)
.emoji({ name: '➡️' })
.disabled(maxPage <= nowPage),
)
.row(
new Button('alert', 'Alerts', noAlert ? 'Secondary' : 'Primary')
.custom_id(city)
.emoji({ name: '⚠️' })
.disabled(noAlert),
deleteButton,
)
return { embeds: [embed], components }
}
const app = new DiscordHono<Env>()
.command('weather', c => {
const isPublic = c.var.public || false
return c.ephemeral(!isPublic).res(weatherInfo(c.var.city || 'default city', 1))
})
.component('weather', c => {
const [city, nowPage]: [string, number] = JSON.parse(c.interaction.data?.custom_id || '')
return c.resUpdate(weatherInfo(city, nowPage))
})
.component('alert', ...)
.component('message-delete', ...)
export default app
// register.ts
const commands = [
new Command('weather', 'weather info').options(
new Option('city', 'city name').required(),
new BooleanOption('public', 'public reply (default: false)'),
),
]
Regarding Bun
As a premise, I have not used Bun yet.
I have not thought about using Bun as a development environment.
I believe that it is possible to use Bun as the user's environment.
If there is an error specific to the Bun environment, I would like to respond to it. (Though I may be late in responding.)
When you run npm run register
, I think you will benefit from the increased processing speed.
However, the actual index.ts
running on cloudflare should be irrelevant.
P.S. I found some improvements in Discord Hono while writing the sample code. Thanks.
Updated to version 0.7.4. The code has been made a little clearer.
// const city = c.interaction.data?.custom_id
const city = c.var.custom_id
Also partially merged the builders. As a breaking change, I expanded the builder's array type argument.
If you are interested, try updating it.
Thanks. Now it was easier to create the command after looking at your examples :D. Here is the command that I was working on. Maybe it will be useful to someone in the future note: a lot of things are in Polish
I'm curious about your plans for embed support in Discord Hono. Are you considering adding built-in support for embeds? If not, then what do you think about this EmbedBuilder class in the attachement I don't want to bother with a pull request as I don't use github, so I'm sharing it here for your consideration. What are your thoughts on this? Also I haven't thoroughly tested or checked this code - it's just an idea I'm putting out there embed.txt