From 230aee97fad1fa358a626621cd1528f7ad97143e Mon Sep 17 00:00:00 2001 From: Jaron Pate Date: Tue, 20 Sep 2022 19:32:41 -0500 Subject: [PATCH] starting to add slash commands --- package.json | 4 +- src/index.ts | 29 +++++++- src/lib/embed.ts | 136 +++++++++++++++++++++++++++++++++++++ src/lib/gateway.ts | 12 +++- src/lib/index.ts | 1 + src/lib/interaction.ts | 34 +++++----- src/lib/message.ts | 38 +++++------ src/types/command.ts | 6 +- src/types/slash_command.ts | 55 +++++++++++++++ test/main.test.ts | 8 ++- 10 files changed, 276 insertions(+), 47 deletions(-) create mode 100644 src/lib/embed.ts create mode 100644 src/types/slash_command.ts diff --git a/package.json b/package.json index ed8bff3..633957f 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,8 @@ "/dist" ], "scripts": { - "start": "npx ts-node-dev src/index.ts", - "start:watch": "npx ts-node-dev --respawn src/index.ts", + "start": "npx ts-node test/main.test.ts", + "start:watch": "npx ts-node-dev --respawn test/main.test.ts", "build": "npx tsc" }, "devDependencies": { diff --git a/src/index.ts b/src/index.ts index d2e6c5f..6dbdaae 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ -import { ComponentStyle, Context, Gateway, Guilds, Message } from './lib'; +import { ComponentStyle, Context, Gateway, Guilds, Message, Embed } from './lib'; import { Command, CommandFuntion, Intent, Presence } from './types'; -export { ComponentStyle, Context, Gateway, Guilds, Message, Command, CommandFuntion, Intent, Presence }; +export { ComponentStyle, Context, Gateway, Guilds, Message, Embed, Command, CommandFuntion, Intent, Presence }; type Config = { token: string; @@ -15,6 +15,7 @@ export class Client { readonly application_id: string; private readonly gateway: Gateway; private readonly client_commands: Map = new Map(); + private readonly slash_commands: Map = new Map(); readonly guilds: Guilds; constructor({ token, application_id, prefix, intents }: Config) { @@ -23,6 +24,8 @@ export class Client { this.prefix = prefix ?? '!'; this.gateway = new Gateway({ token, intents, client: this }); this.guilds = new Guilds({ token, gateway: this.gateway }); + // Do some default stuff + this.initialize(); } get user() { @@ -84,6 +87,28 @@ export class Client { }, delete: (command_name: string) => { this.client_commands.delete(command_name); + }, + list: () => { + return this.client_commands; } }; + + private initialize = () => { + // Register default help command + this.commands.register('help', (client, context, _args) => { + const embed = new Embed().setTitle('Commands').setDescription('This is a list of commands you can use.'); + + const commands = Array.from(client.commands.list().entries()); + + for (const [name, command] of commands) { + embed.addField({ + name: name, + value: command instanceof Command ? command.description : 'No description provided' + }); + } + + context.reply(embed.toMessage()); + }); + } + } diff --git a/src/lib/embed.ts b/src/lib/embed.ts new file mode 100644 index 0000000..bcc7f46 --- /dev/null +++ b/src/lib/embed.ts @@ -0,0 +1,136 @@ +import { Message } from '.'; + +type EmbedFooter = { + text: string; + icon_url?: string; + proxy_icon_url?: string; +}; + +type EmbedImage = { + url?: string; + proxy_url?: string; + height?: number; + width?: number; +}; + +type EmbedVideo = { + url?: string; + height?: number; + width?: number; +}; + +type EmbedField = { + name: string; + value: string; + inline?: boolean; +}; + +export class Embed { + title?: string; + description?: string; + url?: string; + timestamp?: string; + color?: number; + footer?: EmbedFooter; + image?: EmbedImage; + thumbnail?: EmbedImage; + video?: EmbedVideo; + provider?: { + name?: string; + url?: string; + }; + author?: EmbedImage & { + name?: string; + }; + fields?: EmbedField[]; + + constructor() { + this.fields = []; + } + + setTitle = (title: string) => { + this.title = title; + return this; + }; + + setDescription = (description: string) => { + this.description = description; + return this; + }; + + setUrl = (url: string) => { + this.url = url; + return this; + }; + + setTimestamp = (timestamp: string) => { + this.timestamp = timestamp; + return this; + }; + + setColor = (color: number) => { + this.color = color; + return this; + }; + + setFooter = (footer: EmbedFooter) => { + this.footer = footer; + return this; + }; + + setImage = (image: EmbedImage) => { + this.image = image; + return this; + }; + + setThumbnail = (thumbnail: EmbedImage) => { + this.thumbnail = thumbnail; + return this; + }; + + setVideo = (video: EmbedVideo) => { + this.video = video; + return this; + }; + + setProvider = (provider: { name?: string; url?: string }) => { + this.provider = provider; + return this; + }; + + setAuthor = (author: EmbedImage & { name?: string }) => { + this.author = author; + return this; + }; + + addField = (field: EmbedField) => { + this.fields.push(field); + return this; + }; + + addFields = (fields: EmbedField[]) => { + this.fields.push(...fields); + return this; + }; + + toMessage = () => { + return new Message().addEmbed(this); + }; + + toJSON = () => { + return { + title: this.title, + description: this.description, + url: this.url, + timestamp: this.timestamp, + color: this.color, + footer: this.footer, + image: this.image, + thumbnail: this.thumbnail, + video: this.video, + provider: this.provider, + author: this.author, + fields: this.fields + }; + }; +} diff --git a/src/lib/gateway.ts b/src/lib/gateway.ts index f8cd358..526f6f3 100644 --- a/src/lib/gateway.ts +++ b/src/lib/gateway.ts @@ -237,6 +237,16 @@ export class Gateway { }; private handleInteractionCreate = (payload: Payload) => { + if (payload.d.type === 2) { + this.handleShashInteraction(payload); + } else { + this.handleChatInteraction(payload); + } + }; + + private handleShashInteraction = (payload: Payload) => {}; + + private handleChatInteraction = (payload: Payload) => { const context = new InteractionContext({ client: this.client, interaction: payload.d }); const handlers = this.client.interactions.get(payload.d.data.custom_id); if (handlers) { @@ -322,7 +332,7 @@ export class Gateway { } if (data) { console.log('received: %s', data); - console.log('received: %s', data.d); + console.log('received data: %s', data.d); if (this.session && data.s && data.s > this.session.s) { this.session.s = data.s; } else { diff --git a/src/lib/index.ts b/src/lib/index.ts index 0f230cd..7075c9c 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -3,4 +3,5 @@ export * from './cache'; export * from './guilds'; export * from './context'; export * from './message'; +export * from './embed'; export * from './interaction'; diff --git a/src/lib/interaction.ts b/src/lib/interaction.ts index eef604d..3bdb062 100644 --- a/src/lib/interaction.ts +++ b/src/lib/interaction.ts @@ -5,9 +5,11 @@ import { Message } from "./message"; export class InteractionContext { public client: Client; public interaction: Record; - constructor({ client, interaction }: { client: Client; interaction: Record }) { + private is_loading: boolean; + constructor({ client, interaction, is_loading = false }: { client: Client; interaction: Record, is_loading?: boolean }) { this.client = client; this.interaction = interaction; + this.is_loading = is_loading; } ack = (type: InteractionResponseType = InteractionResponseType.Pong, data?: Record) => { @@ -30,22 +32,20 @@ export class InteractionContext { if (typeof message === 'string') { message = new Message().setContent(message); } - return this.ack(InteractionResponseType.UpdateMessage, { - ...message - }); - }; - - editOriginal = (message: Message | string) => { - if (typeof message === 'string') { - message = new Message().setContent(message); - } - return this.client.api.patch( - `/webhooks/${this.client.application_id}/${this.interaction.token}/messages/@original`, - { - type: InteractionResponseType.DeferredUpdateMessage, + if (!this.is_loading) { + return this.ack(InteractionResponseType.UpdateMessage, { ...message - } - ); + }); + } else { + return this.client.api.patch( + `/webhooks/${this.client.application_id}/${this.interaction.token}/messages/@original`, + { + type: InteractionResponseType.DeferredUpdateMessage, + ...message + } + ); + } + }; deleteOriginal = () => { @@ -56,6 +56,6 @@ export class InteractionContext { loading = async () => { await this.ack(InteractionResponseType.DeferredReply); - return new InteractionContext({ client: this.client, interaction: this.interaction }); + return new InteractionContext({ client: this.client, interaction: this.interaction, is_loading: true }); }; } diff --git a/src/lib/message.ts b/src/lib/message.ts index a68fc40..df74202 100644 --- a/src/lib/message.ts +++ b/src/lib/message.ts @@ -1,6 +1,4 @@ -export type Embed = { - -} +import { Embed } from '.'; export type Component = Partial