Updated the README some for rewrite

This commit is contained in:
2025-01-02 01:49:22 -06:00
parent 2f20325c03
commit fc7f6548a4
3 changed files with 109 additions and 21 deletions
+100 -14
View File
@@ -3,22 +3,28 @@
<p>Build good bots fast</p> <p>Build good bots fast</p>
</div> </div>
> This package is in an early Alpha stage and not yet ready for consumption > This package is in an early beta stage and not yet ready for consumption
A solid and simple Discord API wrapper. A solid and simple Discord API wrapper.
## Installation ## Installation
Install with your package manager of choice.
``` ```
yarn add @jaronp/discord.ts npm install discord.ts
yarn add discord.ts
bun add discord.ts
``` ```
## Quick Start ## Quick Start
A small example implementation. A small example implementation.
```ts ```typescript
import { Client } from '@jaronp/discord.ts'; import { Client, type Context } from '`discord.ts';
// Initialize and configure // Initialize and configure
const bot = new Client({ const client = new Client({
token: '<token>', token: '<token>',
application_id: '<application_id>', application_id: '<application_id>',
intents: [ intents: [
@@ -26,26 +32,105 @@ const bot = new Client({
Intent.GUILD_MESSAGES, Intent.GUILD_MESSAGES,
Intent.GUILD_MESSAGE_REACTIONS, Intent.GUILD_MESSAGE_REACTIONS,
Intent.MESSAGE_CONTENT Intent.MESSAGE_CONTENT
] ],
prefix: '??'
}); });
// Register a listener // Register arbitrary event handler to the client bus
bot.handlers.register('READY', (client, context, data) => { client.on('READY', async (_, payload) => {
console.log(`Logged in as ${client.user.tag}`); console.log(`Logged in as ${payload.user.username}${payload.user.discriminator?.length > 0 ? `#${payload.user.discriminator}` : ''}`);
}); });
// Register a command // Register a command
bot.commands.register('ping', (client, context, args) => { client.chatCommands.register('ping', (context: Context, args) => {
context.reply('Pong!', true); context.reply('Pong!', true);
}); });
// Connect // Connect
bot.connect(); client.connect();
``` ```
## Type Resolution and Saftey
This library is designed to be type safe and resolve types for you. Because of this you can write code that is both safe and easy to understand. With the `createCommandHandler` utility you can provide types for command arguments. The client will then check and resolve them for you.
```typescript
import { createCommandHandler, CommandOptionType, type Context } from 'discord.ts';
// <...>
// Define the command handler with the utility function
const avatarCommand = createCommandHandler({
description: 'Get a users avatar',
args: [
{
id: 'user',
name: 'user',
type: CommandOptionType.User,
description: 'The user to get the avatar for',
required: true
}
] as const,
execute: async (context: Context, args) => {
// Args will be typed here as { user: User }
context.reply(args.user.avatarURL);
}
});
// You can then register the command with the client
// The class generated can be used for both chat and application commands
client.chatCommands.register('avatar', avatarCommand);
client.applicationCommands.register('avatar', ApplicationCommandType.Chat, avatarCommand);
// <...>
```
> NOTE: The `as const` is required to ensure the types are resolved correctly. This is to work around some TypeScript weirdness.
## Hydration
Hydration allows you to fetch and fill data on Discord objects. This is useful for when you need to fetch additional data about an object.
```typescript
client.chatCommands.register('ping', async (context: Context, args: any[]) => {
// Hydrate the message id from the context
const { message } = await context.hydrate(context, [Expectation.Message]);
// Send a message to the channel
const response = await context.reply(`Pong!: got ${args.join(', ')}`, true);
// Calculate the time it took to send the message
const time = message.timestamp.getTime() - message.timestamp.getTime();
// Edit the message to include the time
await context.editMessage(response, `Pong! Latency: ${time}ms`);
});
```
This is a powerful feature that allows you to fetch and use data from Discord objects in a type safe way. It also ensures the minimum amount of API calls are made and that no extra data is fetched or passed.
You can also generate a hydration function that returns a type narrowing boolean. This can be used to check if the object is hydrated or not.
```typescript
client.chatCommands.register('me', async (context: Context, _args: any[]) => {
// Hydrate the message id from the context
const hydrate = await context.hydrator(hydrated, [Expectation.Guild]);
// Check if the object is hydrated
const hasGuild = hydrate(hydrated);
if (hasGuild) {
// Send a message stating the user that they are in a guild
await context.reply(`You are ${message.author.username} and this is ${message.guild.name}`, true);
} else {
// Send a message stating the user that they are not in a guild
await context.reply(`You are ${message.author.username} and we are not in a server`, true);
}
});
```
Additionally you can hydrate repeatedly if you need to fetch multiple objects at different times.
<!--
## Interactions ## Interactions
First create the interactions. First create the interactions.
```ts ```typescript
bot.commands.register('test', (_client, context, _args) => { bot.commands.register('test', (_client, context, _args) => {
// Add components to use interactions // Add components to use interactions
const msg = new Message().setContent('Test interaction!').addComponent( const msg = new Message().setContent('Test interaction!').addComponent(
@@ -68,10 +153,11 @@ bot.commands.register('test', (_client, context, _args) => {
}); });
``` ```
Then provide a handler for them. Then provide a handler for them.
```ts ```typescript
bot.interactions.register('click_me', async (client, context, interaction) => { bot.interactions.register('click_me', async (client, context, interaction) => {
const response = context.reply( const response = context.reply(
`You clicked me! Thank you ${interaction.member.user.username} <3` `You clicked me! Thank you ${interaction.member.user.username} <3`
); );
}); });
``` ```
-->
+2 -2
View File
@@ -1,7 +1,7 @@
import { API } from './api'; import { API } from './api';
import { Gateway } from './connectors/gateway'; import { Gateway } from './connectors/gateway';
import { Processor } from './processor'; import { Processor } from './processor';
import { Expectation, fromDiscord, Intent, type ClientConfig } from '../types/common'; import { Expectation, Intent, type ClientConfig } from '../types/common';
import { exists, isNil } from '../utils/index'; import { exists, isNil } from '../utils/index';
import { type DiscordMessage, Message } from '../types/message'; import { type DiscordMessage, Message } from '../types/message';
import { Guilds } from './caches/guilds'; import { Guilds } from './caches/guilds';
@@ -42,7 +42,7 @@ export class Client {
this.guilds = new Guilds(this.api, this.processor); this.guilds = new Guilds(this.api, this.processor);
this.users = new Users(this.api, this.processor); this.users = new Users(this.api, this.processor);
this.messages = new Messages(this, this.api, this.processor); this.messages = new Messages(this, this.api, this.processor);
// Save references to the chat and application command handlers // Save references to command and event handlers
this.chatCommands = this.processor.chat_commands; this.chatCommands = this.processor.chat_commands;
this.applicationCommands = this.processor.application_commands; this.applicationCommands = this.processor.application_commands;
} }
+7 -5
View File
@@ -85,11 +85,13 @@ client.chatCommands.register('me', async (context: Context, _args: any[]) => {
const hydrate = await context.hydrator(hydrated, [Expectation.Guild]); const hydrate = await context.hydrator(hydrated, [Expectation.Guild]);
const hasGuild = hydrate(hydrated); const hasGuild = hydrate(hydrated);
// if (hasGuild) { if (hasGuild) {
// hydrated.guild.name // Send a message stating the user that they are in a guild
// } else { await context.reply(`You are ${message.author.username} and this is ${message.guild.name}`, true);
// hydrated } else {
// } // Send a message stating the user that they are not in a guild
await context.reply(`You are ${message.author.username} and we are not in a server`, true);
}
// await context.reply(`You are ${message.author.username} ${hasGuild ? message.guild.name : ''}`, true); // await context.reply(`You are ${message.author.username} ${hasGuild ? message.guild.name : ''}`, true);
}); });