diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml deleted file mode 100644 index d65aeb3b4..000000000 --- a/.github/workflows/greetings.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Greetings - -on: [pull_request, issues] - -jobs: - greeting: - runs-on: ubuntu-latest - steps: - - uses: actions/first-interaction@v1 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - issue-message: "Thank you for helping contribute to Discordeno. I really do appreciate any and all contributions! Hopefully, together we will be able to make the very best bot Discord API module in the world. Since, this is your very first issue, feel free to look around the repository and then hop on into the Discord server, where you can chat with me directly. https://discord.gg/J4NqJ72" - pr-message: "Thank you for helping contribute to Discordeno. I really do appreciate any and all contributions! Hopefully, together we will be able to make the very best Discord API module in the world. Since, this is your very first pull request, feel free to look around the repository and then hop on into the Discord server, where you can chat with me directly. https://discord.gg/J4NqJ72" diff --git a/README.md b/README.md index 86ecb644b..bd5888489 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,19 @@ > Discord API library wrapper in Deno -[![Discord](https://img.shields.io/discord/223909216866402304?color=7289da&logo=discord&logoColor=white)](https://discord.gg/J4NqJ72) +[![Discord](https://img.shields.io/discord/223909216866402304?color=7289da&logo=discord&logoColor=dark)](https://discord.gg/J4NqJ72) ![Testing/Linting](https://github.com/Skillz4Killz/Discordeno/workflows/Testing/Linting/badge.svg) -[![nest.land](https://nest.land/badge-large.svg)](https://nest.land/package/Discordeno) +[![nest badge](https://nest.land/badge.svg)](https://nest.land/package/Discordeno) -[Website](https://discordeno.netlify.app) +[WIP] ![Test](https://github.com/Skillz4Killz/Discordeno/workflows/Test/badge.svg) -## Beginner Developers +## Why Discordeno? -Don't worry a lot of developers start out coding their first projects as a Discord bot(I did 😉) and it is not so easy. With Discordeno, I tried to build it in a way that solved all the headaches I had when first starting out coding bots. If you are a beginner developer, please use a boilerplate: The official one is at: [GitHub](https://github.com/Skillz4Killz/Discordeno-bot-template) but there will be more listed on the website. It is a beautiful website indeed! Check it out! +### Beginner Developers + +Don't worry a lot of developers start out coding their first projects as a Discord bot (I did 😉) and it is not so easy to do so. Discordeno is built considering all the issues wit pre-existing libraries, such as discord.js, and issues that I had when I first started out coding bots. + +If you are a beginner developer, please use this official boilerplate: [GitHub](https://github.com/Skillz4Killz/Discordeno-bot-template) but there will be more listed on the website. It is a beautiful website indeed! Check it out! **Modular commands, arguments, events, inhibitors, monitors, tasks.** @@ -41,15 +45,10 @@ Don't worry a lot of developers start out coding their first projects as a Disco - Uses i18next, one of the best localization tools available. - Supports nested folders to keep cleaner translation files -**Hot Reloadable** +- **Hot Reloadable**: Easily update your code without having to restart the bot everytime. +- **Step By Step Guide**: There is a step by step walkthrough to learn how to create Discord bots with Discordeno on our website! -- Easily update your code without having to restart the bot everytime. - -**Step By Step Guide** - -- There is a step by step walkthrough to learn how to create Discord bots with Discordeno on our website! - -## Advanced Developers +### Advanced Developers The instructions below are meant for advanced developers! @@ -64,7 +63,7 @@ StartBot({ intents: [Intents.GUILD_MESSAGES, Intents.GUILDS], eventHandlers: { ready: () => { - console.log(`Logged!`); + console.log('Successfully connected to gateway'); }, messageCreate: (message) => { if (message.content === "!ping") { @@ -77,12 +76,13 @@ StartBot({ Alternatively, you can use boilerplate template repositories that were created by wonderful developers. Review the list on the website, and add any of yours if you make your own. -![image](https://i.imgur.com/z1BfUnt.png) +## Documentation -#### Dark Mode +- [API Documentation](https://doc.deno.land/https/deno.land/x/discordeno/mod.ts) +- [Guide](https://discordeno.netlify.com) +- [Support server](https://discord.gg/J4NqJ72) +- [Contributing Guide](https://github.com/Skillz4Killz/Discordeno/blob/master/.github/CONTRIBUTING.md) -![image](https://i.imgur.com/Vr2Bebr.png) +## License -### Tests - -![Test](https://github.com/Skillz4Killz/Discordeno/workflows/Test/badge.svg) \ No newline at end of file +MIT © Skillz4Killz diff --git a/egg.yml b/egg.yml index 408443064..3af7f3b38 100644 --- a/egg.yml +++ b/egg.yml @@ -2,16 +2,16 @@ name: Discordeno description: >- Discord Deno TypeScript API library wrapper(Officially vetted library by Discord Team) https://discordeno.netlify.app -version: 9.0.5 +version: 9.0.12 stable: true entry: mod.ts repository: 'https://github.com/Skillz4Killz/Discordeno' files: - ./src/**/* - LICENSE - - mod.ts - README.md - tsconfig.json - ./deps.ts + - mod.ts checkAll: false unlisted: false diff --git a/src/controllers/roles.ts b/src/controllers/roles.ts index 919499a4a..62cf72eb1 100644 --- a/src/controllers/roles.ts +++ b/src/controllers/roles.ts @@ -48,5 +48,6 @@ export async function handleInternalGuildRoleUpdate(data: DiscordPayload) { if (!cachedRole) return; const role = await structures.createRole(payload.role); + guild.roles.set(payload.role.id, role); eventHandlers.roleUpdate?.(guild, role, cachedRole); } diff --git a/src/handlers/channel.ts b/src/handlers/channel.ts index 881521ea0..0e2580996 100644 --- a/src/handlers/channel.ts +++ b/src/handlers/channel.ts @@ -1,8 +1,10 @@ import { endpoints } from "../constants/discord.ts"; +import { cacheHandlers } from "../controllers/cache.ts"; import { RequestManager } from "../module/requestManager.ts"; import { structures } from "../structures/mod.ts"; -import type { +import { ChannelEditOptions, + ChannelTypes, CreateInviteOptions, FollowedChannelPayload, GetMessages, @@ -160,6 +162,15 @@ export async function sendMessage( } } + const channel = await cacheHandlers.get("channels", channelID); + if (!channel) throw new Error(Errors.CHANNEL_NOT_FOUND); + if ( + ![ChannelTypes.DM, ChannelTypes.GUILD_NEWS, ChannelTypes.GUILD_TEXT] + .includes(channel.type) + ) { + throw new Error(Errors.CHANNEL_NOT_TEXT_BASED); + } + const result = await RequestManager.post( endpoints.CHANNEL_MESSAGES(channelID), { diff --git a/src/module/basicShard.ts b/src/module/basicShard.ts index 60717ca3c..68b9196ff 100644 --- a/src/module/basicShard.ts +++ b/src/module/basicShard.ts @@ -51,7 +51,7 @@ export async function createBasicShard( const basicShard: BasicShard = { id: shardID, - socket: await connectWebSocket(`${data.url}?v=6&encoding=json`), + socket: await connectWebSocket(`${data.url}?v=8&encoding=json`), resumeInterval: 0, sessionID: oldShard?.sessionID || "", previousSequenceNumber: oldShard?.previousSequenceNumber || 0, diff --git a/src/module/requestManager.ts b/src/module/requestManager.ts index 8d37a14fb..c74abe25c 100644 --- a/src/module/requestManager.ts +++ b/src/module/requestManager.ts @@ -286,6 +286,23 @@ async function runMethod( }); } +async function logErrors(response: Response, errorStack?: unknown) { + try { + const error = await response.json(); + console.error(error); + + eventHandlers.debug?.({ type: "error", data: { errorStack, error } }); + } catch { + eventHandlers.debug?.( + { + type: "error", + data: { errorStack }, + }, + ); + console.error(response); + } +} + function handleStatusCode(response: Response, errorStack?: unknown) { const status = response.status; @@ -296,13 +313,7 @@ function handleStatusCode(response: Response, errorStack?: unknown) { return true; } - eventHandlers.debug?.( - { - type: "error", - data: { errorStack }, - }, - ); - console.error(response); + logErrors(response, errorStack); switch (status) { case HttpResponseCode.BadRequest: diff --git a/src/types/activity.ts b/src/types/activity.ts index 0299625ff..cc8110d87 100644 --- a/src/types/activity.ts +++ b/src/types/activity.ts @@ -1,12 +1,18 @@ -import type { Timestamps } from "./discord.ts"; - export interface ActivityPayload { name: string; type: number; url?: string; created_at: number; - timestamps: Timestamps; + timestamps?: ActivityTimestamps; + application_id?: string; details?: string; + state?: string; + emoji?: ActivityEmoji; + party?: ActivityParty; + assets?: ActivityAssets; + secrets?: ActivitySecrets; + instance?: boolean; + flags?: number; } export enum ActivityType { @@ -21,3 +27,41 @@ export enum ActivityType { /** Example: "Competing in Arena World Champions" */ Competing, } + +export interface ActivityTimestamps { + start?: number; + end?: number; +} + +export interface ActivityEmoji { + name: string; + id?: string; + animated?: boolean; +} + +export interface ActivityParty { + id?: string; + size?: [number, number]; +} + +export interface ActivityAssets { + large_image?: string; + large_text?: string; + small_image?: string; + small_text?: string; +} + +export interface ActivitySecrets { + join?: string; + spectate?: string; + match?: string; +} + +export enum ActivityFlags { + INSTANCE = 1 << 0, + JOIN = 1 << 1, + SPECTATE = 1 << 2, + JOIN_REQUEST = 1 << 3, + SYNC = 1 << 4, + PLAY = 1 << 5, +} diff --git a/src/types/discord.ts b/src/types/discord.ts index 161c15b59..58e08b343 100644 --- a/src/types/discord.ts +++ b/src/types/discord.ts @@ -196,11 +196,6 @@ export interface Properties { $device: string; } -export interface Timestamps { - start?: number; - end?: number; -} - export interface Emoji { name: string; id?: string; diff --git a/src/types/errors.ts b/src/types/errors.ts index da321ff35..98df112d2 100644 --- a/src/types/errors.ts +++ b/src/types/errors.ts @@ -31,4 +31,6 @@ export enum Errors { CHANNEL_NOT_IN_GUILD = "CHANNEL_NOT_IN_GUILD", INVALID_WEBHOOK_NAME = "INVALID_WEBHOOK_NAME", INVALID_WEBHOOK_OPTIONS = "INVALID_WEBHOOK_OPTIONS", + CHANNEL_NOT_FOUND = "CHANNEL_NOT_FOUND", + CHANNEL_NOT_TEXT_BASED = "CHANNEL_NOT_TEXT_BASED", } diff --git a/src/utils/permissions.ts b/src/utils/permissions.ts index d904a401c..f69ec570b 100644 --- a/src/utils/permissions.ts +++ b/src/utils/permissions.ts @@ -34,6 +34,8 @@ export function memberHasPermission( const permissionBits = memberRoleIDs.map((id) => guild.roles.get(id)?.permissions ) + // Removes any edge case undefined + .filter((id) => id) .reduce((bits, permissions) => { bits |= BigInt(permissions); return bits; @@ -86,13 +88,18 @@ export async function hasChannelPermissions( permissions: Permissions[], ) { const channel = await cacheHandlers.get("channels", channelID); - if (!channel?.guildID) return true; + if (!channel) return false; + if (!channel.guildID) return true; const guild = await cacheHandlers.get("guilds", channel.guildID); if (!guild) return false; if (guild.ownerID === memberID) return true; - if (botHasPermission(guild.id, [Permissions.ADMINISTRATOR])) return true; + if ( + await memberIDHasPermission(memberID, guild.id, ["ADMINISTRATOR"]) + ) { + return true; + } const member = guild.members.get(memberID); if (!member) return false;