From d5a8207690cb85ed669780098a5c2c3587a48bb5 Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Mon, 22 Feb 2021 23:07:17 +0900 Subject: [PATCH 01/11] Export CommandsLoader class too --- mod.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mod.ts b/mod.ts index bc096bb..c46282d 100644 --- a/mod.ts +++ b/mod.ts @@ -14,7 +14,8 @@ export { CommandBuilder, CommandCategory, CommandsManager, - CategoriesManager + CategoriesManager, + CommandsLoader } from './src/models/command.ts' export type { CommandContext, CommandOptions } from './src/models/command.ts' export { From de089ce610871d81223c6763525cba83c7a6c385 Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Tue, 23 Feb 2021 12:09:38 +0900 Subject: [PATCH 02/11] Add request data to error --- src/models/rest.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/models/rest.ts b/src/models/rest.ts index daab5d1..2914d2e 100644 --- a/src/models/rest.ts +++ b/src/models/rest.ts @@ -37,6 +37,7 @@ export interface DiscordAPIErrorPayload { code?: number message?: string errors: object + requestData: { [key: string]: any } } export class DiscordAPIError extends Error { @@ -319,7 +320,9 @@ export class RESTManager { } } const form = new FormData() - files.forEach((file, index) => form.append(`file${index + 1}`, file.blob, file.name)) + files.forEach((file, index) => + form.append(`file${index + 1}`, file.blob, file.name) + ) const json = JSON.stringify(body) form.append('payload_json', json) if (body === undefined) body = {} @@ -465,7 +468,8 @@ export class RESTManager { ).map((entry) => { return [entry[0], entry[1]._errors ?? []] }) - ) + ), + requestData: data } // if (typeof error.errors === 'object') { From 548b6bf2ad3a9fd0816635059ce8e2489994863e Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Tue, 23 Feb 2021 12:13:46 +0900 Subject: [PATCH 03/11] Fix guildChannelManager.create SMALL bracket mistake --- src/managers/guildChannels.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/managers/guildChannels.ts b/src/managers/guildChannels.ts index 9d86342..2bc6837 100644 --- a/src/managers/guildChannels.ts +++ b/src/managers/guildChannels.ts @@ -66,8 +66,7 @@ export class GuildChannelsManager extends BaseChildManager< async create(options: CreateChannelOptions): Promise { if (options.name === undefined) throw new Error('name is required for GuildChannelsManager#create') - const res = ((await this.client.rest.post(GUILD_CHANNELS(this.guild.id)), - { + const res = ((await this.client.rest.post(GUILD_CHANNELS(this.guild.id), { name: options.name, type: options.type, topic: options.topic, @@ -83,7 +82,7 @@ export class GuildChannelsManager extends BaseChildManager< ? options.parent.id : options.parent, nsfw: options.nsfw - }) as unknown) as GuildChannelPayload + })) as unknown) as GuildChannelPayload await this.set(res.id, res) const channel = await this.get(res.id) From ff80750ca40b3429f421d186019abd382fe2496d Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Tue, 23 Feb 2021 13:07:27 +0900 Subject: [PATCH 04/11] Fix bitfield type error --- src/test/index.ts | 8 ++++++++ src/utils/bitfield.ts | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/test/index.ts b/src/test/index.ts index 1d3d7d9..d68e245 100644 --- a/src/test/index.ts +++ b/src/test/index.ts @@ -211,6 +211,14 @@ client.on('messageCreate', async (msg: Message) => { msg.member as Member ) msg.channel.send(`Your permissions:\n${permissions.toArray().join('\n')}`) + } else if (msg.content === '!addAllRoles') { + const roles = await msg.guild?.roles.array() + if (roles !== undefined) { + roles.forEach(async (role) => { + await msg.member?.roles.add(role) + console.log(role) + }) + } } }) diff --git a/src/utils/bitfield.ts b/src/utils/bitfield.ts index 8631f1f..cb8a93c 100644 --- a/src/utils/bitfield.ts +++ b/src/utils/bitfield.ts @@ -104,11 +104,11 @@ export class BitField { if (bit instanceof BitField) return this.resolve(flags, bit.bitfield) if (Array.isArray(bit)) return (bit.map as any)((p: any) => this.resolve(flags, p)).reduce( - (prev: any, p: any) => prev | p, + (prev: bigint, p: bigint) => prev | p, 0 ) if (typeof bit === 'string' && typeof flags[bit] !== 'undefined') - return flags[bit] + return BigInt(flags[bit]) const error = new RangeError('BITFIELD_INVALID') throw error } From 8e5a76dbe85393fbe79e918e5827f5905536e70f Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Tue, 23 Feb 2021 13:47:14 +0900 Subject: [PATCH 05/11] Fix the real problem part --- src/test/index.ts | 8 ++++++++ src/utils/bitfield.ts | 7 +++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/test/index.ts b/src/test/index.ts index d68e245..e1321a7 100644 --- a/src/test/index.ts +++ b/src/test/index.ts @@ -219,6 +219,14 @@ client.on('messageCreate', async (msg: Message) => { console.log(role) }) } + } else if (msg.content === '!createAndAddRole') { + if (msg.guild !== undefined) { + const role = await msg.guild.roles.create({ + name: 'asdf', + permissions: 0 + }) + await msg.member?.roles.add(role) + } } }) diff --git a/src/utils/bitfield.ts b/src/utils/bitfield.ts index cb8a93c..9e77396 100644 --- a/src/utils/bitfield.ts +++ b/src/utils/bitfield.ts @@ -14,7 +14,10 @@ export class BitField { #flags: { [name: string]: number | bigint } = {} bitfield: bigint - constructor(flags: { [name: string]: number | bigint }, bits: any) { + constructor( + flags: { [name: string]: number | bigint }, + bits: BitFieldResolvable + ) { this.#flags = flags this.bitfield = BitField.resolve(this.#flags, bits) } @@ -105,7 +108,7 @@ export class BitField { if (Array.isArray(bit)) return (bit.map as any)((p: any) => this.resolve(flags, p)).reduce( (prev: bigint, p: bigint) => prev | p, - 0 + 0n ) if (typeof bit === 'string' && typeof flags[bit] !== 'undefined') return BigInt(flags[bit]) From 2b0db63f82e7be1dece84939ee017b5b93f96d47 Mon Sep 17 00:00:00 2001 From: DjDeveloper <43033058+DjDeveloperr@users.noreply.github.com> Date: Tue, 23 Feb 2021 13:31:55 +0530 Subject: [PATCH 06/11] fix(cache): guild props being removed before saving to cache --- src/managers/guilds.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/managers/guilds.ts b/src/managers/guilds.ts index 8faf478..772f476 100644 --- a/src/managers/guilds.ts +++ b/src/managers/guilds.ts @@ -147,6 +147,7 @@ export class GuildManager extends BaseManager { /** Sets a value to Cache */ async set(key: string, value: GuildPayload): Promise { + value = { ...value } if ('roles' in value) value.roles = [] if ('emojis' in value) value.emojis = [] if ('members' in value) value.members = [] From d5634f676fa20311b6efb4b4213586550a38b355 Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Thu, 25 Feb 2021 13:23:01 +0900 Subject: [PATCH 07/11] Ready to publish on nest.land --- .eggignore | 3 +++ README.md | 2 ++ egg.json | 23 +++++++++++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 .eggignore create mode 100644 egg.json diff --git a/.eggignore b/.eggignore new file mode 100644 index 0000000..ecde67e --- /dev/null +++ b/.eggignore @@ -0,0 +1,3 @@ +extends .gitignore +./src/test/**/* + diff --git a/README.md b/README.md index d2191f7..7e21d05 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ You can import the package from https://deno.land/x/harmony/mod.ts (with latest version) or can add a version too, and raw GitHub URL (latest unpublished version) https://raw.githubusercontent.com/harmonyland/harmony/main/mod.ts too. +You can also check(not import) the module in https://nest.land/package/harmony (link for importing is in the site). + For a quick example, run this: ```bash diff --git a/egg.json b/egg.json new file mode 100644 index 0000000..fc8d036 --- /dev/null +++ b/egg.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://x.nest.land/eggs@0.3.4/src/schema.json", + "name": "harmony", + "entry": "./mod.ts", + "description": "An easy to use Discord API Library for Deno.", + "homepage": "https://github.com/harmonyland/harmony", + "version": "v1.1.3", + "files": [ + "./src/**/*", + "./deps.ts", + "./README.md", + "./LICENSE", + "./banner.png", + "./CONTRIBUTING.md", + "./CODE_OF_CONDUCT.md", + "./examples/*" + ], + "checkFormat": "npx eslint src", + "checkTests": false, + "checkInstallation": false, + "check": true, + "unlisted": false +} From 30fa9429c57dbacb6bf30e0fbb383acd31600537 Mon Sep 17 00:00:00 2001 From: DjDeveloperr Date: Thu, 25 Feb 2021 15:59:42 +0530 Subject: [PATCH 08/11] intents no longer needed for ping example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7e21d05..f750ffe 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ For a quick example, run this: deno run --allow-net https://deno.land/x/harmony/examples/ping.ts ``` -And input your bot's token and Intents. +And input your bot's token. Here is a small example of how to use harmony, From 00dae42f7bb929b888d4f19dbe0b0d6e761db200 Mon Sep 17 00:00:00 2001 From: DjDeveloperr Date: Thu, 25 Feb 2021 16:15:13 +0530 Subject: [PATCH 09/11] add AsyncInterator support for Managers --- src/managers/base.ts | 7 +++++++ src/managers/baseChild.ts | 7 +++++++ src/test/index.ts | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/src/managers/base.ts b/src/managers/base.ts index e522d31..442b7fc 100644 --- a/src/managers/base.ts +++ b/src/managers/base.ts @@ -60,6 +60,13 @@ export class BaseManager { return collection } + async *[Symbol.asyncIterator](): AsyncIterableIterator { + const arr = (await this.array()) ?? [] + const { readable, writable } = new TransformStream() + arr.forEach((el) => writable.getWriter().write(el)) + yield* readable.getIterator() + } + /** Deletes everything from Cache */ flush(): any { return this.client.cache.deleteCache(this.cacheName) diff --git a/src/managers/baseChild.ts b/src/managers/baseChild.ts index adc96f8..0842859 100644 --- a/src/managers/baseChild.ts +++ b/src/managers/baseChild.ts @@ -39,4 +39,11 @@ export class BaseChildManager { } return collection } + + async *[Symbol.asyncIterator](): AsyncIterableIterator { + const arr = (await this.array()) ?? [] + const { readable, writable } = new TransformStream() + arr.forEach((el: unknown) => writable.getWriter().write(el)) + yield* readable.getIterator() + } } diff --git a/src/test/index.ts b/src/test/index.ts index e1321a7..b635041 100644 --- a/src/test/index.ts +++ b/src/test/index.ts @@ -227,6 +227,13 @@ client.on('messageCreate', async (msg: Message) => { }) await msg.member?.roles.add(role) } + } else if (msg.content === '!roles') { + let buf = 'Roles:' + if (msg.member === undefined) return + for await (const role of msg.member.roles) { + buf += `\n${role.name}` + } + msg.reply(buf) } }) From d26059fdc8c00ce415b3d1ea88fe11dcd4c75176 Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Thu, 4 Mar 2021 10:50:55 +0900 Subject: [PATCH 10/11] Export invite manager --- egg.json | 3 ++- mod.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/egg.json b/egg.json index fc8d036..43e6d96 100644 --- a/egg.json +++ b/egg.json @@ -19,5 +19,6 @@ "checkTests": false, "checkInstallation": false, "check": true, - "unlisted": false + "unlisted": false, + "ignore": [] } diff --git a/mod.ts b/mod.ts index c46282d..fdd25de 100644 --- a/mod.ts +++ b/mod.ts @@ -43,6 +43,7 @@ export { ReactionUsersManager } from './src/managers/reactionUsers.ts' export { MessagesManager } from './src/managers/messages.ts' export { RolesManager } from './src/managers/roles.ts' export { UsersManager } from './src/managers/users.ts' +export { InviteManager } from './src/managers/invites.ts' export { Application } from './src/structures/application.ts' // export { ImageURL } from './src/structures/cdn.ts' export { Channel } from './src/structures/channel.ts' From 88519d942049dd021a3e6e48a89202a48b64bbcf Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Thu, 4 Mar 2021 21:13:50 +0900 Subject: [PATCH 11/11] Add missing cdn functions, dynamic image format --- src/structures/cdn.ts | 12 +++++---- src/structures/emoji.ts | 16 ++++++++++- src/structures/guild.ts | 60 ++++++++++++++++++++++++++++++++++++++++- src/types/cdn.ts | 2 +- 4 files changed, 82 insertions(+), 8 deletions(-) diff --git a/src/structures/cdn.ts b/src/structures/cdn.ts index 83ff27c..78c8495 100644 --- a/src/structures/cdn.ts +++ b/src/structures/cdn.ts @@ -3,11 +3,13 @@ import { ImageFormats, ImageSize } from '../types/cdn.ts' /** Function to get Image URL from a resource on Discord CDN */ export const ImageURL = ( url: string, - format: ImageFormats | undefined = 'png', - size: ImageSize | undefined = 128 + format: ImageFormats = 'png', + size: ImageSize = 128 ): string => { - size = size === undefined ? 128 : size if (url.includes('a_')) { - return `${url}.${format === undefined ? 'gif' : format}?size=${size}` - } else return `${url}.${format === 'gif' ? 'png' : format}?size=${size}` + return `${url}.${format === 'dynamic' ? 'gif' : format}?size=${size}` + } else + return `${url}.${ + format === 'gif' || format === 'dynamic' ? 'png' : format + }?size=${size}` } diff --git a/src/structures/emoji.ts b/src/structures/emoji.ts index fe71889..19cd8e1 100644 --- a/src/structures/emoji.ts +++ b/src/structures/emoji.ts @@ -1,8 +1,10 @@ import { Client } from '../models/client.ts' +import { ImageSize } from '../types/cdn.ts' import { EmojiPayload } from '../types/emoji.ts' -import { EMOJI } from '../types/endpoint.ts' +import { CUSTOM_EMOJI, EMOJI } from '../types/endpoint.ts' import { Snowflake } from '../utils/snowflake.ts' import { Base } from './base.ts' +import { ImageURL } from './cdn.ts' import { Guild } from './guild.ts' import { Role } from './role.ts' import { User } from './user.ts' @@ -54,6 +56,18 @@ export class Emoji extends Base { this.available = data.available } + /** + * Gets emoji image URL + */ + emojiImageURL( + format: 'png' | 'gif' | 'dynamic' = 'png', + size: ImageSize = 512 + ): string | undefined { + return this.id != null + ? `${ImageURL(CUSTOM_EMOJI(this.id), format, size)}` + : undefined + } + /** Modify the given emoji. Requires the MANAGE_EMOJIS permission. Returns the updated emoji object on success. Fires a Guild Emojis Update Gateway event. */ async edit(data: ModifyGuildEmojiParams): Promise { if (this.id === null) throw new Error('Emoji ID is not valid.') diff --git a/src/structures/guild.ts b/src/structures/guild.ts index 11a9d93..81bbca7 100644 --- a/src/structures/guild.ts +++ b/src/structures/guild.ts @@ -32,9 +32,13 @@ import { User } from './user.ts' import { Application } from './application.ts' import { GUILD_BAN, + GUILD_BANNER, GUILD_BANS, + GUILD_DISCOVERY_SPLASH, + GUILD_ICON, GUILD_INTEGRATIONS, - GUILD_PRUNE + GUILD_PRUNE, + GUILD_SPLASH } from '../types/endpoint.ts' import { GuildVoiceStatesManager } from '../managers/guildVoiceStates.ts' import { RequestMembersOptions } from '../gateway/index.ts' @@ -42,6 +46,8 @@ import { GuildPresencesManager } from '../managers/presences.ts' import { TemplatePayload } from '../types/template.ts' import { Template } from './template.ts' import { DiscordAPIError } from '../models/rest.ts' +import { ImageFormats, ImageSize } from '../types/cdn.ts' +import { ImageURL } from './cdn.ts' export class GuildBan extends Base { guild: Guild @@ -258,6 +264,58 @@ export class Guild extends SnowflakeBase { } } + /** + * Gets guild icon URL + */ + iconURL( + format: ImageFormats = 'png', + size: ImageSize = 512 + ): string | undefined { + return this.icon != null + ? `${ImageURL(GUILD_ICON(this.id, this.icon), format, size)}` + : undefined + } + + /** + * Gets guild splash URL + */ + splashURL( + format: ImageFormats = 'png', + size: ImageSize = 512 + ): string | undefined { + return this.splash != null + ? `${ImageURL(GUILD_SPLASH(this.id, this.splash), format, size)}` + : undefined + } + + /** + * Gets guild discover splash URL + */ + discoverSplashURL( + format: ImageFormats = 'png', + size: ImageSize = 512 + ): string | undefined { + return this.discoverySplash != null + ? `${ImageURL( + GUILD_DISCOVERY_SPLASH(this.id, this.discoverySplash), + format, + size + )}` + : undefined + } + + /** + * Gets guild banner URL + */ + bannerURL( + format: ImageFormats = 'png', + size: ImageSize = 512 + ): string | undefined { + return this.banner != null + ? `${ImageURL(GUILD_BANNER(this.id, this.banner), format, size)}` + : undefined + } + /** * Gets Everyone role of the Guild */ diff --git a/src/types/cdn.ts b/src/types/cdn.ts index 4fbfc13..b78bd48 100644 --- a/src/types/cdn.ts +++ b/src/types/cdn.ts @@ -1,2 +1,2 @@ export type ImageSize = 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 -export type ImageFormats = 'jpg' | 'jpeg' | 'png' | 'webp' | 'gif' +export type ImageFormats = 'jpg' | 'jpeg' | 'png' | 'webp' | 'gif' | 'dynamic'