public interface tweaks and such
This commit is contained in:
@@ -25,43 +25,6 @@ import type { ReacordInstance } from "./instance"
|
|||||||
import type { ReacordConfig } from "./reacord"
|
import type { ReacordConfig } from "./reacord"
|
||||||
import { Reacord } from "./reacord"
|
import { Reacord } from "./reacord"
|
||||||
|
|
||||||
/**
|
|
||||||
* Options for the channel message.
|
|
||||||
*
|
|
||||||
* @see https://reacord.mapleleaf.dev/guides/sending-messages
|
|
||||||
*/
|
|
||||||
export interface LegacyCreateChannelMessageOptions
|
|
||||||
extends CreateChannelMessageOptions {
|
|
||||||
/**
|
|
||||||
* Send message as a reply. Requires the use of message event instead of
|
|
||||||
* channel id provided as argument.
|
|
||||||
*
|
|
||||||
* @deprecated Use reacord.createMessageReply()
|
|
||||||
*/
|
|
||||||
reply?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Options for the channel message.
|
|
||||||
*
|
|
||||||
* @see https://reacord.mapleleaf.dev/guides/sending-messages
|
|
||||||
*/
|
|
||||||
export interface CreateChannelMessageOptions {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Options for the message reply method.
|
|
||||||
*
|
|
||||||
* @see https://reacord.mapleleaf.dev/guides/sending-messages
|
|
||||||
*/
|
|
||||||
export interface CreateMessageReplyOptions {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom options for the interaction reply method.
|
|
||||||
*
|
|
||||||
* @see https://reacord.mapleleaf.dev/guides/sending-messages
|
|
||||||
*/
|
|
||||||
export type CreateInteractionReplyOptions = ReplyInfo
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Reacord adapter for Discord.js.
|
* The Reacord adapter for Discord.js.
|
||||||
*
|
*
|
||||||
@@ -86,45 +49,31 @@ export class ReacordDiscordJs extends Reacord {
|
|||||||
/**
|
/**
|
||||||
* Sends a message to a channel.
|
* Sends a message to a channel.
|
||||||
*
|
*
|
||||||
* @param target - Discord channel object.
|
* @param target Discord channel object.
|
||||||
* @param [options] - Options for the channel message
|
* @param [options] Options for the channel message
|
||||||
* @see https://reacord.mapleleaf.dev/guides/sending-messages
|
* @see https://reacord.mapleleaf.dev/guides/sending-messages
|
||||||
|
* @see {@link Discord.MessageCreateOptions}
|
||||||
*/
|
*/
|
||||||
public createChannelMessage(
|
public createChannelMessage(
|
||||||
target: Discord.Channel,
|
target: Discord.ChannelResolvable,
|
||||||
options: CreateChannelMessageOptions = {},
|
options: Discord.MessageCreateOptions = {},
|
||||||
): ReacordInstance {
|
): ReacordInstance {
|
||||||
return this.createInstance(
|
return this.createInstance(
|
||||||
this.createChannelMessageRenderer(target, options),
|
this.createChannelMessageRenderer(target, options),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Replies to a message by sending a message.
|
|
||||||
*
|
|
||||||
* @param message - Discord message event object.
|
|
||||||
* @param [options] - Options for the message reply method.
|
|
||||||
* @see https://reacord.mapleleaf.dev/guides/sending-messages
|
|
||||||
*/
|
|
||||||
public createMessageReply(
|
|
||||||
message: Discord.Message,
|
|
||||||
options: CreateMessageReplyOptions = {},
|
|
||||||
): ReacordInstance {
|
|
||||||
return this.createInstance(
|
|
||||||
this.createMessageReplyRenderer(message, options),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replies to a command interaction by sending a message.
|
* Replies to a command interaction by sending a message.
|
||||||
*
|
*
|
||||||
* @param interaction - Discord command interaction object.
|
* @param interaction Discord command interaction object.
|
||||||
* @param [options] - Custom options for the interaction reply method.
|
* @param [options] Custom options for the interaction reply method.
|
||||||
* @see https://reacord.mapleleaf.dev/guides/sending-messages
|
* @see https://reacord.mapleleaf.dev/guides/sending-messages
|
||||||
|
* @see {@link Discord.InteractionReplyOptions}
|
||||||
*/
|
*/
|
||||||
public createInteractionReply(
|
public createInteractionReply(
|
||||||
interaction: Discord.CommandInteraction,
|
interaction: Discord.CommandInteraction,
|
||||||
options: CreateInteractionReplyOptions = {},
|
options: Discord.InteractionReplyOptions = {},
|
||||||
): ReacordInstance {
|
): ReacordInstance {
|
||||||
return this.createInstance(
|
return this.createInstance(
|
||||||
this.createInteractionReplyRenderer(interaction, options),
|
this.createInteractionReplyRenderer(interaction, options),
|
||||||
@@ -132,19 +81,17 @@ export class ReacordDiscordJs extends Reacord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a message to a channel. Alternatively replies to message event.
|
* Sends a message to a channel.
|
||||||
*
|
*
|
||||||
* @deprecated Use reacord.createChannelMessage() or
|
* @deprecated Use reacord.createChannelMessage() instead.
|
||||||
* reacord.createMessageReply() instead.
|
|
||||||
* @see https://reacord.mapleleaf.dev/guides/sending-messages
|
* @see https://reacord.mapleleaf.dev/guides/sending-messages
|
||||||
*/
|
*/
|
||||||
public send(
|
public send(
|
||||||
event: string | Discord.Message,
|
channel: Discord.ChannelResolvable,
|
||||||
initialContent?: React.ReactNode,
|
initialContent?: React.ReactNode,
|
||||||
options: LegacyCreateChannelMessageOptions = {},
|
|
||||||
): ReacordInstance {
|
): ReacordInstance {
|
||||||
return this.createInstance(
|
return this.createInstance(
|
||||||
this.createMessageReplyRenderer(event, options),
|
this.createChannelMessageRenderer(channel, {}),
|
||||||
initialContent,
|
initialContent,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -158,10 +105,9 @@ export class ReacordDiscordJs extends Reacord {
|
|||||||
public reply(
|
public reply(
|
||||||
interaction: Discord.CommandInteraction,
|
interaction: Discord.CommandInteraction,
|
||||||
initialContent?: React.ReactNode,
|
initialContent?: React.ReactNode,
|
||||||
options: CreateInteractionReplyOptions = {},
|
|
||||||
): ReacordInstance {
|
): ReacordInstance {
|
||||||
return this.createInstance(
|
return this.createInstance(
|
||||||
this.createInteractionReplyRenderer(interaction, options),
|
this.createInteractionReplyRenderer(interaction, {}),
|
||||||
initialContent,
|
initialContent,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -169,18 +115,16 @@ export class ReacordDiscordJs extends Reacord {
|
|||||||
/**
|
/**
|
||||||
* Sends an ephemeral message as a reply to a command interaction.
|
* Sends an ephemeral message as a reply to a command interaction.
|
||||||
*
|
*
|
||||||
* @deprecated Use reacord.createInteractionReply(interaction, content, {
|
* @deprecated Use reacord.createInteractionReply(interaction, { ephemeral:
|
||||||
* ephemeral: true })
|
* true })
|
||||||
* @see https://reacord.mapleleaf.dev/guides/sending-messages
|
* @see https://reacord.mapleleaf.dev/guides/sending-messages
|
||||||
*/
|
*/
|
||||||
public ephemeralReply(
|
public ephemeralReply(
|
||||||
interaction: Discord.CommandInteraction,
|
interaction: Discord.CommandInteraction,
|
||||||
initialContent?: React.ReactNode,
|
initialContent?: React.ReactNode,
|
||||||
options?: Omit<CreateInteractionReplyOptions, "ephemeral">,
|
|
||||||
): ReacordInstance {
|
): ReacordInstance {
|
||||||
return this.createInstance(
|
return this.createInstance(
|
||||||
this.createInteractionReplyRenderer(interaction, {
|
this.createInteractionReplyRenderer(interaction, {
|
||||||
...options,
|
|
||||||
ephemeral: true,
|
ephemeral: true,
|
||||||
}),
|
}),
|
||||||
initialContent,
|
initialContent,
|
||||||
@@ -188,49 +132,32 @@ export class ReacordDiscordJs extends Reacord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private createChannelMessageRenderer(
|
private createChannelMessageRenderer(
|
||||||
channel: Discord.Channel,
|
channelResolvable: Discord.ChannelResolvable,
|
||||||
_opts?: CreateMessageReplyOptions,
|
messageCreateOptions?: Discord.MessageCreateOptions,
|
||||||
) {
|
) {
|
||||||
return new ChannelMessageRenderer({
|
return new ChannelMessageRenderer({
|
||||||
send: async (options) => {
|
send: async (messageOptions) => {
|
||||||
if (!channel.isTextBased()) {
|
let channel = this.client.channels.resolve(channelResolvable)
|
||||||
raise(`Channel ${channel.id} is not a text channel`)
|
if (!channel && typeof channelResolvable === "string") {
|
||||||
|
channel = await this.client.channels.fetch(channelResolvable)
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = await channel.send(getDiscordMessageOptions(options))
|
if (!channel) {
|
||||||
return createReacordMessage(message)
|
const id =
|
||||||
},
|
typeof channelResolvable === "string"
|
||||||
})
|
? channelResolvable
|
||||||
}
|
: channelResolvable.id
|
||||||
|
raise(`Channel ${id} not found`)
|
||||||
private createMessageReplyRenderer(
|
}
|
||||||
event: string | Discord.Message,
|
|
||||||
opts: CreateChannelMessageOptions | LegacyCreateChannelMessageOptions,
|
|
||||||
) {
|
|
||||||
return new ChannelMessageRenderer({
|
|
||||||
send: async (options) => {
|
|
||||||
// Backwards compatible channelId api
|
|
||||||
// `event` is treated as MessageEvent depending on its type
|
|
||||||
const channel =
|
|
||||||
typeof event === "string"
|
|
||||||
? this.client.channels.cache.get(event) ??
|
|
||||||
(await this.client.channels.fetch(event)) ??
|
|
||||||
raise(`Channel ${event} not found`)
|
|
||||||
: event.channel
|
|
||||||
|
|
||||||
if (!channel.isTextBased()) {
|
if (!channel.isTextBased()) {
|
||||||
raise(`Channel ${channel.id} is not a text channel`)
|
raise(`Channel ${channel.id} must be a text channel`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("reply" in opts && opts.reply) {
|
const message = await channel.send({
|
||||||
if (typeof event === "string") {
|
...getDiscordMessageOptions(messageOptions),
|
||||||
raise("Cannot send reply with channel ID provided")
|
...messageCreateOptions,
|
||||||
}
|
})
|
||||||
|
|
||||||
const message = await event.reply(getDiscordMessageOptions(options))
|
|
||||||
return createReacordMessage(message)
|
|
||||||
}
|
|
||||||
const message = await channel.send(getDiscordMessageOptions(options))
|
|
||||||
return createReacordMessage(message)
|
return createReacordMessage(message)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -240,23 +167,22 @@ export class ReacordDiscordJs extends Reacord {
|
|||||||
interaction:
|
interaction:
|
||||||
| Discord.CommandInteraction
|
| Discord.CommandInteraction
|
||||||
| Discord.MessageComponentInteraction,
|
| Discord.MessageComponentInteraction,
|
||||||
opts: CreateInteractionReplyOptions,
|
interactionReplyOptions: Discord.InteractionReplyOptions,
|
||||||
) {
|
) {
|
||||||
return new InteractionReplyRenderer({
|
return new InteractionReplyRenderer({
|
||||||
type: "command",
|
interactionId: interaction.id,
|
||||||
id: interaction.id,
|
reply: async (messageOptions) => {
|
||||||
reply: async (options) => {
|
|
||||||
const message = await interaction.reply({
|
const message = await interaction.reply({
|
||||||
...getDiscordMessageOptions(options),
|
...getDiscordMessageOptions(messageOptions),
|
||||||
...opts,
|
...interactionReplyOptions,
|
||||||
fetchReply: true,
|
fetchReply: true,
|
||||||
})
|
})
|
||||||
return createReacordMessage(message)
|
return createReacordMessage(message)
|
||||||
},
|
},
|
||||||
followUp: async (options) => {
|
followUp: async (messageOptions) => {
|
||||||
const message = await interaction.followUp({
|
const message = await interaction.followUp({
|
||||||
...getDiscordMessageOptions(options),
|
...getDiscordMessageOptions(messageOptions),
|
||||||
...opts,
|
...interactionReplyOptions,
|
||||||
fetchReply: true,
|
fetchReply: true,
|
||||||
})
|
})
|
||||||
return createReacordMessage(message)
|
return createReacordMessage(message)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { Interaction } from "../interaction"
|
|
||||||
import type { Message, MessageOptions } from "../message"
|
import type { Message, MessageOptions } from "../message"
|
||||||
import { Renderer } from "./renderer"
|
import { Renderer } from "./renderer"
|
||||||
|
|
||||||
@@ -6,17 +5,23 @@ import { Renderer } from "./renderer"
|
|||||||
// so we know whether to call reply() or followUp()
|
// so we know whether to call reply() or followUp()
|
||||||
const repliedInteractionIds = new Set<string>()
|
const repliedInteractionIds = new Set<string>()
|
||||||
|
|
||||||
|
export type InteractionReplyRendererImplementation = {
|
||||||
|
interactionId: string
|
||||||
|
reply: (options: MessageOptions) => Promise<Message>
|
||||||
|
followUp: (options: MessageOptions) => Promise<Message>
|
||||||
|
}
|
||||||
|
|
||||||
export class InteractionReplyRenderer extends Renderer {
|
export class InteractionReplyRenderer extends Renderer {
|
||||||
constructor(private interaction: Interaction) {
|
constructor(private implementation: InteractionReplyRendererImplementation) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected createMessage(options: MessageOptions): Promise<Message> {
|
protected createMessage(options: MessageOptions): Promise<Message> {
|
||||||
if (repliedInteractionIds.has(this.interaction.id)) {
|
if (repliedInteractionIds.has(this.implementation.interactionId)) {
|
||||||
return this.interaction.followUp(options)
|
return this.implementation.followUp(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
repliedInteractionIds.add(this.interaction.id)
|
repliedInteractionIds.add(this.implementation.interactionId)
|
||||||
return this.interaction.reply(options)
|
return this.implementation.reply(options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ slug: getting-started
|
|||||||
|
|
||||||
# Getting Started
|
# Getting Started
|
||||||
|
|
||||||
These guides assume some familiarity with JavaScript, [React](https://reactjs.org), [Discord.js](https://discord.js.org) and the [Discord API](https://discord.dev). Keep these pages as reference if you need it.
|
These guides assume some familiarity with [JavaScript](https://developer.mozilla.org/en-US/docs/Web/javascript), [React](https://reactjs.org), [Discord.js](https://discord.js.org) and the [Discord API](https://discord.dev). Keep these pages as reference if you need it.
|
||||||
|
|
||||||
## Setup from template
|
## Setup from template
|
||||||
|
|
||||||
@@ -47,6 +47,13 @@ await client.login(process.env.BOT_TOKEN)
|
|||||||
To use JSX in your code, run it with [tsx](https://npm.im/tsx):
|
To use JSX in your code, run it with [tsx](https://npm.im/tsx):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install tsx
|
npm install -D tsx
|
||||||
tsx main.tsx
|
npx tsx main.tsx
|
||||||
|
```
|
||||||
|
|
||||||
|
For production, I recommend compiling it with [tsup](https://npm.im/tsup):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install -D tsup
|
||||||
|
npx tsup src/main.tsx --target node20
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ function Uptime() {
|
|||||||
|
|
||||||
client.on("ready", () => {
|
client.on("ready", () => {
|
||||||
const instance = reacord.createChannelMessage(channel)
|
const instance = reacord.createChannelMessage(channel)
|
||||||
|
|
||||||
instance.render(<Uptime />)
|
instance.render(<Uptime />)
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
@@ -48,26 +47,25 @@ const Hello = ({ subject }) => <>Hello, {subject}!</>
|
|||||||
|
|
||||||
client.on("ready", () => {
|
client.on("ready", () => {
|
||||||
const instance = reacord.createChannelMessage(channel)
|
const instance = reacord.createChannelMessage(channel)
|
||||||
|
|
||||||
instance.render(<Hello subject="World" />)
|
instance.render(<Hello subject="World" />)
|
||||||
instance.render(<Hello subject="Moon" />)
|
instance.render(<Hello subject="Moon" />)
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
## Replying to Messages
|
You can specify various options for the message:
|
||||||
|
|
||||||
Instead of sending messages to a channel, you may want to reply to a specific message instead. To do this, create an instance using `.createMessageReply()` instead:
|
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
const Hello = ({ username }) => <>Hello, {username}!</>
|
const instance = reacord.createChannelMessage(channel, {
|
||||||
|
tts: true,
|
||||||
client.on("messageCreate", (message) => {
|
reply: {
|
||||||
reacord
|
messageReference: someMessage.id,
|
||||||
.createMessageReply(message)
|
},
|
||||||
.render(<Hello username={message.author.displayName} />)
|
flags: [MessageFlags.SuppressNotifications],
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See the [Discord.js docs](https://discord.js.org/#/docs/discord.js/main/typedef/MessageCreateOptions) for all of the available options.
|
||||||
|
|
||||||
## Cleaning Up Instances
|
## Cleaning Up Instances
|
||||||
|
|
||||||
If you no longer want to use the instance, you can clean it up in a few ways:
|
If you no longer want to use the instance, you can clean it up in a few ways:
|
||||||
@@ -91,7 +89,7 @@ const reacord = new ReacordDiscordJs(client, {
|
|||||||
This section also applies to other kinds of application commands, such as context menu commands.
|
This section also applies to other kinds of application commands, such as context menu commands.
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
To reply to a command interaction, use the `.createInteractionReply()` function. This function returns an instance that works the same way as the one from `.createChannelMessage()` and `.createMessageReply()`. Here's an example:
|
To reply to a command interaction, use the `.createInteractionReply()` function. This function returns an instance that works the same way as the one from `.createChannelMessage()`. Here's an example:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
import { Client } from "discord.js"
|
import { Client } from "discord.js"
|
||||||
@@ -163,11 +161,7 @@ handleCommands(client, [
|
|||||||
])
|
])
|
||||||
```
|
```
|
||||||
|
|
||||||
## Interaction Options
|
## Ephemeral Command Replies
|
||||||
|
|
||||||
Just like `.createChannelMessage()` and `.createMessageReply()`, interaction replies provide a way to specify certain `interaction.reply()` options.
|
|
||||||
|
|
||||||
### Ephemeral Command Replies
|
|
||||||
|
|
||||||
Ephemeral replies are replies that only appear for one user. To create them, use the `.createInteractionReply()` function and provide `ephemeral` option.
|
Ephemeral replies are replies that only appear for one user. To create them, use the `.createInteractionReply()` function and provide `ephemeral` option.
|
||||||
|
|
||||||
@@ -185,7 +179,7 @@ handleCommands(client, [
|
|||||||
])
|
])
|
||||||
```
|
```
|
||||||
|
|
||||||
### Text-to-Speech Command Replies
|
## Text-to-Speech Command Replies
|
||||||
|
|
||||||
Additionally interaction replies may have `tts` option to turn on text-to-speech ability for the reply. To create such reply, use `.createInteractionReply()` function and provide `tts` option.
|
Additionally interaction replies may have `tts` option to turn on text-to-speech ability for the reply. To create such reply, use `.createInteractionReply()` function and provide `tts` option.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user