From 4bb34c9087e2ba1a2ad7c36212d958b595c9d93b Mon Sep 17 00:00:00 2001 From: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> Date: Mon, 27 Feb 2023 22:08:38 -0600 Subject: [PATCH 1/4] fix: more props that need permission transforming (#2804) --- packages/rest/src/manager.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/rest/src/manager.ts b/packages/rest/src/manager.ts index 41dbeddc5..7576f650f 100644 --- a/packages/rest/src/manager.ts +++ b/packages/rest/src/manager.ts @@ -665,11 +665,17 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage const newObj: any = {} for (const key of Object.keys(obj)) { - if (key === 'permissions') { - newObj.permissions = calculateBits(obj[key]) + // Keys that dont require snake casing + if (['permissions', 'allow', 'deny'].includes(key)) { + newObj[key] = calculateBits(obj[key]) continue } + if (key === 'defaultMemberPermissions') { + newObj.default_member_permissions = calculateBits(obj[key]); + continue; + } + newObj[camelToSnakeCase(key)] = rest.changeToDiscordFormat(obj[key]) } From 80a37f33b3f06d46e277f413dbabc9f61295100c Mon Sep 17 00:00:00 2001 From: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> Date: Mon, 27 Feb 2023 22:19:37 -0600 Subject: [PATCH 2/4] fix: type errors in nayu (#2805) --- packages/client/src/Client.ts | 20 +- packages/client/src/Constants.ts | 560 ++++++++++++++++++ packages/client/src/Structures/Message.ts | 5 +- .../client/src/Structures/guilds/Guild.ts | 4 +- packages/client/src/index.ts | 1 + 5 files changed, 578 insertions(+), 12 deletions(-) create mode 100644 packages/client/src/Constants.ts diff --git a/packages/client/src/Client.ts b/packages/client/src/Client.ts index 824abac77..050d374d7 100644 --- a/packages/client/src/Client.ts +++ b/packages/client/src/Client.ts @@ -27,6 +27,7 @@ import { delay, getBotIdFromToken, iconBigintToHash, iconHashToBigInt } from '@d import EventEmitter from 'node:events' import Base from './Base.js' import Collection from './Collection.js' +import { Intents, IntentStrings } from './Constants.js' import { CHANNEL, CHANNEL_BULK_DELETE, @@ -258,6 +259,8 @@ export class Client extends EventEmitter { constructor(token: string, options: ClientOptions) { super() + this.token = token + this.options = { apiVersion: options.apiVersion ?? 10, allowedMentions: this._formatAllowedMentions(options.allowedMentions), @@ -265,7 +268,7 @@ export class Client extends EventEmitter { defaultImageSize: options.defaultImageSize ?? 128, proxyURL: options.proxyURL, proxyRestAuthorization: options.proxyRestAuthorization, - applicationId: options.applicationId, + applicationId: options.applicationId ?? this.id, messageLimit: options.messageLimit, seedVoiceConnections: options.seedVoiceConnections ?? true, shardConcurrency: options.shardConcurrency ?? 'auto', @@ -275,13 +278,12 @@ export class Client extends EventEmitter { firstShardID: options.firstShardID ?? 0, lastShardID: options.lastShardID, maxResumeAttempts: options.maxResumeAttempts ?? Infinity, - intents: options.intents ?? 0, + intents: typeof options.intents === "number" ? options.intents : Array.isArray(options.intents) ? options.intents.reduce((bits, intent) => (typeof intent === "number" ? intent | bits : Intents[intent]), 0) : 0, autoreconnect: options.autoreconnect ?? true, guildCreateTimeout: options.guildCreateTimeout ?? 2000, reconnectDelay: options.reconnectDelay ?? ((lastDelay, attempts) => Math.pow(attempts + 1, 0.7) * 20000), } - this.token = token this.guildShardMap = {} this.requestHandler = new RequestHandler(this, {}) @@ -2357,15 +2359,15 @@ export interface ClientOptions { /** The message limit you would like to set. */ messageLimit?: number /** The api version you would like to use. */ - apiVersion: ApiVersions + apiVersion?: ApiVersions /** The url to the REST proxy to send requests to. This url should nly include the initial domain:port portion until api/v.... */ - proxyURL: string + proxyURL?: string /** The password/authorization to confirm that these request made to your rest proxy are indeed from you and not a hacker. */ - proxyRestAuthorization: string + proxyRestAuthorization?: string /** The application id(NOT the bot id). The bot id and application id are the same for newer bots but older bots have different ids. */ - applicationId: BigString + applicationId?: BigString /** Whether or not to seed voice connections. */ - seedVoiceConnections: boolean + seedVoiceConnections?: boolean /** The concurrency to use when starting the bot. */ shardConcurrency?: 'auto' | number /** How many shards to use max. */ @@ -2379,7 +2381,7 @@ export interface ClientOptions { /** How many times to attempt resuming. */ maxResumeAttempts?: number /** The intents to use when connection to gateway. */ - intents?: GatewayIntents + intents?: GatewayIntents | number | (IntentStrings | number)[] /** Whether or not to automatically reconnect to gateway. */ autoreconnect?: boolean /** diff --git a/packages/client/src/Constants.ts b/packages/client/src/Constants.ts new file mode 100644 index 000000000..969231d8e --- /dev/null +++ b/packages/client/src/Constants.ts @@ -0,0 +1,560 @@ +export const GATEWAY_VERSION = 9; +export const REST_VERSION = 9; + +export const ActivityTypes = { + GAME: 0, + STREAMING: 1, + LISTENING: 2, + WATCHING: 3, + CUSTOM: 4, + COMPETING: 5 +}; + +export const ApplicationCommandOptionTypes = { + SUB_COMMAND: 1, + SUB_COMMAND_GROUP: 2, + STRING: 3, + INTEGER: 4, + BOOLEAN: 5, + USER: 6, + CHANNEL: 7, + ROLE: 8, + MENTIONABLE: 9, + NUMBER: 10 +}; + +export const ApplicationCommandPermissionTypes = { + ROLE: 1, + USER: 2 +}; + +export const ApplicationCommandTypes = { + CHAT_INPUT: 1, + USER: 2, + MESSAGE: 3 +}; + +export const AuditLogActions = { + GUILD_UPDATE: 1, + + CHANNEL_CREATE: 10, + CHANNEL_UPDATE: 11, + CHANNEL_DELETE: 12, + CHANNEL_OVERWRITE_CREATE: 13, + CHANNEL_OVERWRITE_UPDATE: 14, + CHANNEL_OVERWRITE_DELETE: 15, + + MEMBER_KICK: 20, + MEMBER_PRUNE: 21, + MEMBER_BAN_ADD: 22, + MEMBER_BAN_REMOVE: 23, + MEMBER_UPDATE: 24, + MEMBER_ROLE_UPDATE: 25, + MEMBER_MOVE: 26, + MEMBER_DISCONNECT: 27, + BOT_ADD: 28, + + ROLE_CREATE: 30, + ROLE_UPDATE: 31, + ROLE_DELETE: 32, + + INVITE_CREATE: 40, + INVITE_UPDATE: 41, + INVITE_DELETE: 42, + + WEBHOOK_CREATE: 50, + WEBHOOK_UPDATE: 51, + WEBHOOK_DELETE: 52, + + EMOJI_CREATE: 60, + EMOJI_UPDATE: 61, + EMOJI_DELETE: 62, + + MESSAGE_DELETE: 72, + MESSAGE_BULK_DELETE: 73, + MESSAGE_PIN: 74, + MESSAGE_UNPIN: 75, + + INTEGRATION_CREATE: 80, + INTEGRATION_UPDATE: 81, + INTEGRATION_DELETE: 82, + + STAGE_INSTANCE_CREATE: 83, + STAGE_INSTANCE_UPDATE: 84, + STAGE_INSTANCE_DELETE: 85, + + STICKER_CREATE: 90, + STICKER_UPDATE: 91, + STICKER_DELETE: 92, + + GUILD_SCHEDULED_EVENT_CREATE: 100, + GUILD_SCHEDULED_EVENT_UPDATE: 101, + GUILD_SCHEDULED_EVENT_DELETE: 102, + + THREAD_CREATE: 110, + THREAD_UPDATE: 111, + THREAD_DELETE: 112, + + APPLICATION_COMMAND_PERMISSION_UPDATE: 121 +}; + +export const ButtonStyles = { + PRIMARY: 1, + SECONDARY: 2, + SUCCESS: 3, + DANGER: 4, + LINK: 5 +}; + +export const ChannelTypes = { + GUILD_TEXT: 0, + DM: 1, + GUILD_VOICE: 2, + GROUP_DM: 3, + GUILD_CATEGORY: 4, + GUILD_NEWS: 5, + GUILD_STORE: 6, + + GUILD_NEWS_THREAD: 10, + GUILD_PUBLIC_THREAD: 11, + GUILD_PRIVATE_THREAD: 12, + GUILD_STAGE_VOICE: 13, GUILD_STAGE: 13 // [DEPRECATED] +}; + +export const ComponentTypes = { + ACTION_ROW: 1, + BUTTON: 2, + SELECT_MENU: 3 +}; + +export const ConnectionVisibilityTypes = { + NONE: 0, + EVERYONE: 1 +}; + +export const DefaultMessageNotificationLevels = { + ALL_MESSAGES: 0, + ONLY_MENTIONS: 1 +}; + +export const ExplicitContentFilterLevels = { + DISABLED: 0, + MEMBERS_WITHOUT_ROLES: 1, + ALL_MEMBERS: 2 +}; + +export const GatewayOPCodes = { + DISPATCH: 0, EVENT: 0, // [DEPRECATED] + HEARTBEAT: 1, + IDENTIFY: 2, + PRESENCE_UPDATE: 3, STATUS_UPDATE: 3, // [DEPRECATED] + VOICE_STATE_UPDATE: 4, + VOICE_SERVER_PING: 5, + RESUME: 6, + RECONNECT: 7, + REQUEST_GUILD_MEMBERS: 8, GET_GUILD_MEMBERS: 8, // [DEPRECATED] + INVALID_SESSION: 9, + HELLO: 10, + HEARTBEAT_ACK: 11, + SYNC_GUILD: 12, + SYNC_CALL: 13 +}; + +export const GuildFeatures = [ + "ANIMATED_ICON", + "BANNER", + "COMMERCE", + "COMMUNITY", + "DISCOVERABLE", + "FEATURABLE", + "INVITE_SPLASH", + "MEMBER_VERIFICATION_GATE_ENABLED", + "MONETIZATION_ENABLED", + "MORE_STICKERS", + "NEWS", + "PARTNERED", + "PREVIEW_ENABLED", + "PRIVATE_THREADS", + "ROLE_ICONS", + "ROLE_SUBSCRIPTIONS_ENABLED", + "SEVEN_DAY_THREAD_ARCHIVE", + "THREE_DAY_THREAD_ARCHIVE", + "TICKETED_EVENTS_ENABLED", + "VANITY_URL", + "VERIFIED", + "VIP_REGIONS", + "WELCOME_SCREEN_ENABLED" +]; + +export const GuildIntegrationExpireBehavior = { + REMOVE_ROLE: 0, + KICK: 1 +}; +export const GuildIntegrationTypes = [ + "twitch", + "youtube", + "discord" +]; + +export const GuildNSFWLevels = { + DEFAULT: 0, + EXPLICIT: 1, + SAFE: 2, + AGE_RESTRICTED: 3 +}; + +export const ImageFormats = [ + "jpg", + "jpeg", + "png", + "webp", + "gif" +]; + +export const ImageSizeBoundaries = { + MINIMUM: 16, + MAXIMUM: 4096 +}; + +export const Intents = { + guilds: 1 << 0, + guildMembers: 1 << 1, + guildBans: 1 << 2, + guildEmojisAndStickers: 1 << 3, guildEmojis: 1 << 3, // [DEPRECATED] + guildIntegrations: 1 << 4, + guildWebhooks: 1 << 5, + guildInvites: 1 << 6, + guildVoiceStates: 1 << 7, + guildPresences: 1 << 8, + guildMessages: 1 << 9, + guildMessageReactions: 1 << 10, + guildMessageTyping: 1 << 11, + directMessages: 1 << 12, + directMessageReactions: 1 << 13, + directMessageTyping: 1 << 14, + + guildScheduledEvents: 1 << 16, + // Override these below + allNonPrivileged: 0, + allPrivileged: 0, + all: 0, +}; + +Intents.allNonPrivileged = Intents.guilds + | Intents.guildBans + | Intents.guildEmojisAndStickers + | Intents.guildIntegrations + | Intents.guildWebhooks + | Intents.guildInvites + | Intents.guildVoiceStates + | Intents.guildMessages + | Intents.guildMessageReactions + | Intents.guildMessageTyping + | Intents.directMessages + | Intents.directMessageReactions + | Intents.directMessageTyping + | Intents.guildScheduledEvents; +Intents.allPrivileged = Intents.guildMembers + | Intents.guildPresences; +Intents.all = Intents.allNonPrivileged | Intents.allPrivileged; + +export const InteractionResponseTypes = { + PONG: 1, + CHANNEL_MESSAGE_WITH_SOURCE: 4, + DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE: 5, + DEFERRED_UPDATE_MESSAGE: 6, + UPDATE_MESSAGE: 7, + APPLICATION_COMMAND_AUTOCOMPLETE_RESULT: 8 +}; + +export const InteractionTypes = { + PING: 1, + APPLICATION_COMMAND: 2, + MESSAGE_COMPONENT: 3, + APPLICATION_COMMAND_AUTOCOMPLETE: 4 +}; + +export const MFALevels = { + NONE: 0, + ELEVATED: 1 +}; + +export const MessageActivityFlags = { + INSTANCE: 1 << 0, + JOIN: 1 << 1, + SPECTATE: 1 << 2, + JOIN_REQUEST: 1 << 3, + SYNC: 1 << 4, + PLAY: 1 << 5, + PARTY_PRIVACY_FRIENDS: 1 << 6, + PARTY_PRIVACY_VOICE_CHANNEL: 1 << 7, + EMBEDDED: 1 << 8 +}; + +export const MessageActivityTypes = { + JOIN: 1, + SPECTATE: 2, + LISTEN: 3, + JOIN_REQUEST: 5 +}; + +export const MessageTypes = { + DEFAULT: 0, + RECIPIENT_ADD: 1, + RECIPIENT_REMOVE: 2, + CALL: 3, + CHANNEL_NAME_CHANGE: 4, + CHANNEL_ICON_CHANGE: 5, + CHANNEL_PINNED_MESSAGE: 6, + GUILD_MEMBER_JOIN: 7, + USER_PREMIUM_GUILD_SUBSCRIPTION: 8, + USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1: 9, + USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2: 10, + USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3: 11, + CHANNEL_FOLLOW_ADD: 12, + + GUILD_DISCOVERY_DISQUALIFIED: 14, + GUILD_DISCOVERY_REQUALIFIED: 15, + GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING: 16, + GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING: 17, + THREAD_CREATED: 18, + REPLY: 19, + CHAT_INPUT_COMMAND: 20, + THREAD_STARTER_MESSAGE: 21, + GUILD_INVITE_REMINDER: 22, + CONTEXT_MENU_COMMAND: 23 +}; + +export const PermissionOverwriteTypes = { + ROLE: 0, + USER: 1 +}; + +export const Permissions = { + createInstantInvite: 1n << 0n, + kickMembers: 1n << 1n, + banMembers: 1n << 2n, + administrator: 1n << 3n, + manageChannels: 1n << 4n, + manageGuild: 1n << 5n, + addReactions: 1n << 6n, + viewAuditLog: 1n << 7n, viewAuditLogs: 1n << 7n, // [DEPRECATED] + voicePrioritySpeaker: 1n << 8n, + voiceStream: 1n << 9n, stream: 1n << 9n, // [DEPRECATED] + viewChannel: 1n << 10n, readMessages: 1n << 10n, // [DEPRECATED] + sendMessages: 1n << 11n, + sendTTSMessages: 1n << 12n, + manageMessages: 1n << 13n, + embedLinks: 1n << 14n, + attachFiles: 1n << 15n, + readMessageHistory: 1n << 16n, + mentionEveryone: 1n << 17n, + useExternalEmojis: 1n << 18n, externalEmojis: 1n << 18n, // [DEPRECATED] + viewGuildInsights: 1n << 19n, + voiceConnect: 1n << 20n, + voiceSpeak: 1n << 21n, + voiceMuteMembers: 1n << 22n, + voiceDeafenMembers: 1n << 23n, + voiceMoveMembers: 1n << 24n, + voiceUseVAD: 1n << 25n, + changeNickname: 1n << 26n, + manageNicknames: 1n << 27n, + manageRoles: 1n << 28n, + manageWebhooks: 1n << 29n, + manageEmojisAndStickers: 1n << 30n, manageEmojis: 1n << 30n, // [DEPRECATED] + useApplicationCommands: 1n << 31n, useSlashCommands: 1n << 31n, // [DEPRECATED] + voiceRequestToSpeak: 1n << 32n, + manageEvents: 1n << 33n, + manageThreads: 1n << 34n, + createPublicThreads: 1n << 35n, + createPrivateThreads: 1n << 36n, + useExternalStickers: 1n << 37n, + sendMessagesInThreads: 1n << 38n, + startEmbeddedActivities: 1n << 39n, + moderateMembers: 1n << 40n, + // Override these below + all: 0n, + allText: 0n, + allVoice: 0n, + allGuild: 0n, +}; +Permissions.allGuild = Permissions.kickMembers + | Permissions.banMembers + | Permissions.administrator + | Permissions.manageChannels + | Permissions.manageGuild + | Permissions.viewAuditLog + | Permissions.viewGuildInsights + | Permissions.changeNickname + | Permissions.manageNicknames + | Permissions.manageRoles + | Permissions.manageWebhooks + | Permissions.manageEmojisAndStickers + | Permissions.manageEvents + | Permissions.moderateMembers; +Permissions.allText = Permissions.createInstantInvite + | Permissions.manageChannels + | Permissions.addReactions + | Permissions.viewChannel + | Permissions.sendMessages + | Permissions.sendTTSMessages + | Permissions.manageMessages + | Permissions.embedLinks + | Permissions.attachFiles + | Permissions.readMessageHistory + | Permissions.mentionEveryone + | Permissions.useExternalEmojis + | Permissions.manageRoles + | Permissions.manageWebhooks + | Permissions.useApplicationCommands + | Permissions.manageThreads + | Permissions.createPublicThreads + | Permissions.createPrivateThreads + | Permissions.useExternalStickers + | Permissions.sendMessagesInThreads; +Permissions.allVoice = Permissions.createInstantInvite + | Permissions.manageChannels + | Permissions.voicePrioritySpeaker + | Permissions.voiceStream + | Permissions.viewChannel + | Permissions.voiceConnect + | Permissions.voiceSpeak + | Permissions.voiceMuteMembers + | Permissions.voiceDeafenMembers + | Permissions.voiceMoveMembers + | Permissions.voiceUseVAD + | Permissions.manageRoles + | Permissions.voiceRequestToSpeak + | Permissions.startEmbeddedActivities; +Permissions.all = Permissions.allGuild | Permissions.allText | Permissions.allVoice; + +export const PremiumTiers = { + NONE: 0, + TIER_1: 1, + TIER_2: 2, + TIER_3: 3 +}; + +export const GuildScheduledEventStatus = { + SCHEDULED: 1, + ACTIVE: 2, + COMPLETED: 3, + CANCELED: 4 +}; + +export const GuildScheduledEventEntityTypes = { + STAGE_INSTANCE: 1, + VOICE: 2, + EXTERNAL: 3 +}; + +export const GuildScheduledEventPrivacyLevel = { + PUBLIC: 1, + GUILD_ONLY: 2 +}; + +export const PremiumTypes = { + NONE: 0, + NITRO_CLASSIC: 1, + NITRO: 2 +}; + +export const StageInstancePrivacyLevel = { + PUBLIC: 1, + GUILD_ONLY: 2 +}; + +export const StickerFormats = { + PNG: 1, + APNG: 2, + LOTTIE: 3 +}; + +export const StickerTypes = { + STANDARD: 1, + GUILD: 2 +}; + +export const SystemChannelFlags = { + SUPPRESS_JOIN_NOTIFICATIONS: 1 << 0, + SUPPRESS_PREMIUM_SUBSCRIPTIONS: 1 << 1, + SUPPRESS_GUILD_REMINDER_NOTIFICATIONS: 1 << 2, + SUPPRESS_JOIN_NOTIFICATION_REPLIES : 1 << 3 +}; + +export const SystemJoinMessages = [ + "%user% joined the party.", + "%user% is here.", + "Welcome, %user%. We hope you brought pizza.", + "A wild %user% appeared.", + "%user% just landed.", + "%user% just slid into the server.", + "%user% just showed up!", + "Welcome %user%. Say hi!", + "%user% hopped into the server.", + "Everyone welcome %user%!", + "Glad you're here, %user%.", + "Good to see you, %user%.", + "Yay you made it, %user%!" +]; + +export const ThreadMemberFlags = { + HAS_INTERACTED: 1 << 0, + ALL_MESSAGES: 1 << 1, + ONLY_MENTIONS: 1 << 2, + NO_MESSAGES: 1 << 3 +}; + +export const UserFlags = { + NONE: 0, + DISCORD_STAFF: 1 << 0, DISCORD_EMPLOYEE: 1 << 0, + PARTNER: 1 << 1, PARTNERED_SERVER_OWNER: 1 << 1, DISCORD_PARTNER: 1 << 1, // [DEPRECATED] + HYPESQUAD: 1 << 2, HYPESQUAD_EVENTS: 1 << 2, + BUG_HUNTER_LEVEL_1: 1 << 3, + HOUSE_BRAVERY: 1 << 6, HYPESQUAD_ONLINE_HOUSE_1: 1 << 6, + HOUSE_BRILLIANCE: 1 << 7, HYPESQUAD_ONLINE_HOUSE_2: 1 << 7, + HOUSE_BALANCE: 1 << 8, HYPESQUAD_ONLINE_HOUSE_3: 1 << 8, + PREMIUM_EARLY_SUPPORTER: 1 << 9, EARLY_SUPPORTER: 1 << 9, + TEAM_PSEUDO_USER: 1 << 10, TEAM_USER: 1 << 10, + SYSTEM: 1 << 12, + BUG_HUNTER_LEVEL_2: 1 << 14, + VERIFIED_BOT: 1 << 16, + VERIFIED_DEVELOPER: 1 << 17, EARLY_VERIFIED_BOT_DEVELOPER: 1 << 17, VERIFIED_BOT_DEVELOPER: 1 << 17, + CERTIFIED_MODERATOR: 1 << 18, DISCORD_CERTIFIED_MODERATOR: 1 << 18, + BOT_HTTP_INTERACTIONS: 1 << 19 +}; + +export const VerificationLevels = { + NONE: 0, + LOW: 1, + MEDIUM: 2, + HIGH: 3, + VERY_HIGH: 4 +}; + +export const VideoQualityModes = { + AUTO: 1, + FULL: 2 +}; + +export const VoiceOPCodes = { + IDENTIFY: 0, + SELECT_PROTOCOL: 1, + READY: 2, + HEARTBEAT: 3, + SESSION_DESCRIPTION: 4, + SPEAKING: 5, + HEARTBEAT_ACK: 6, + RESUME: 7, + HELLO: 8, + RESUMED: 9, + CLIENT_DISCONNECT: 13, DISCONNECT: 13 // [DEPRECATED] +}; + +export const WebhookTypes = { + INCOMING: 1, + CHANNEL_FOLLOWER: 2, + APPLICATION: 3 +}; + +export type IntentStrings = keyof typeof Intents; \ No newline at end of file diff --git a/packages/client/src/Structures/Message.ts b/packages/client/src/Structures/Message.ts index eec64a58a..2cf4cbb39 100644 --- a/packages/client/src/Structures/Message.ts +++ b/packages/client/src/Structures/Message.ts @@ -21,7 +21,9 @@ import { MessageFlags, type GetMessageReactionOptions, type MessageContentEdit, import type NewsChannel from './channels/News.js' import type PrivateChannel from './channels/Private.js' import type TextChannel from './channels/Text.js' +import type TextVoiceChannel from './channels/TextVoice.js' import type NewsThreadChannel from './channels/threads/NewsThread.js' +import type PrivateThreadChannel from './channels/threads/PrivateThread.js' import type PublicThreadChannel from './channels/threads/PublicThread.js' import type Guild from './guilds/Guild.js' import Member from './guilds/Member.js' @@ -35,7 +37,7 @@ export class Message extends Base { /** The type of the message */ type: MessageTypes /** The channel the message is in. Can be partial with only the id if the channel is not cached. */ - channel: PrivateChannel | TextChannel | NewsChannel | { id: string } + channel: PrivateChannel | TextChannel | NewsChannel | NewsThreadChannel | PublicThreadChannel | PrivateThreadChannel | TextVoiceChannel /** The message content. */ content: string /** An object containing the reactions on the message. Each key is a reaction emoji and each value is an object with properties `me` (Boolean) and `count` (Number) for that specific reaction emoji. */ @@ -111,6 +113,7 @@ export class Message extends Base { this.type = data.type || MessageTypes.Default this.timestamp = Date.parse(data.timestamp) + // @ts-expect-error eris js hack this.channel = this.client.getChannel(data.channel_id) ?? { id: data.channel_id, } diff --git a/packages/client/src/Structures/guilds/Guild.ts b/packages/client/src/Structures/guilds/Guild.ts index f97780d2a..913798ca8 100644 --- a/packages/client/src/Structures/guilds/Guild.ts +++ b/packages/client/src/Structures/guilds/Guild.ts @@ -139,7 +139,7 @@ export class Guild extends Base { /** When this guild was joined at. */ joinedAt: number /** The amount of members in the guild. */ - memberCount?: number + memberCount: number /** The approximate member count in the guild. */ approximateMemberCount?: number /** The approximate presence count in the guild. */ @@ -193,7 +193,7 @@ export class Guild extends Base { this.unavailable = !!data.unavailable this.joinedAt = Date.parse(data.joined_at!) - this.memberCount = data.member_count + this.memberCount = data.member_count ?? 0 this.applicationID = data.application_id this.widgetEnabled = !!data.widget_enabled diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index 502966dfd..814fae492 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -4,6 +4,7 @@ export default Client export * from './Base.js' export * from './Client.js' export * from './Collection.js' +export * from './Constants.js' export * from './Endpoints.js' export * from './gateway/Shard.js' export * from './gateway/ShardManager.js' From e48b9a16c663d5bc03538785c57d65c3e6328e70 Mon Sep 17 00:00:00 2001 From: Jonathan Ho Date: Mon, 27 Feb 2023 20:46:07 -0800 Subject: [PATCH 3/4] ci: update website path (#2806) --- .github/workflows/site.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/site.yml b/.github/workflows/site.yml index c10cdf81d..5e7410675 100644 --- a/.github/workflows/site.yml +++ b/.github/workflows/site.yml @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest defaults: run: - working-directory: ./site + working-directory: ./website # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it @@ -55,7 +55,7 @@ jobs: - name: Upload artifact uses: actions/upload-pages-artifact@v1 with: - path: ./site/build + path: ./website/build deploy: environment: name: github-pages From cf121a870ec1b0d64bec7aca9dd75506c8ef2cdc Mon Sep 17 00:00:00 2001 From: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> Date: Mon, 27 Feb 2023 23:08:09 -0600 Subject: [PATCH 4/4] Fix: more client eris mismatches (#2807) * fix: type errors in nayu * fix: optional file arg in createmessage * fix: add ClientEvents hack * fix: add DiscordRESTError * fix: fmt * fix: fmt * fix: shard prop on guild * fix: permission.has type --- packages/client/src/Client.ts | 5 +- packages/client/src/Constants.ts | 3 +- packages/client/src/Structures/Permission.ts | 5 +- .../client/src/Structures/channels/Private.ts | 2 +- .../client/src/Structures/channels/Text.ts | 2 +- .../client/src/Structures/guilds/Guild.ts | 5 + packages/client/src/index.ts | 2 + packages/client/src/typings.ts | 92 +++++++++++++++++++ packages/client/src/utils/DiscordRESTError.ts | 86 +++++++++++++++++ 9 files changed, 195 insertions(+), 7 deletions(-) create mode 100644 packages/client/src/utils/DiscordRESTError.ts diff --git a/packages/client/src/Client.ts b/packages/client/src/Client.ts index 050d374d7..d65405e6a 100644 --- a/packages/client/src/Client.ts +++ b/packages/client/src/Client.ts @@ -27,7 +27,8 @@ import { delay, getBotIdFromToken, iconBigintToHash, iconHashToBigInt } from '@d import EventEmitter from 'node:events' import Base from './Base.js' import Collection from './Collection.js' -import { Intents, IntentStrings } from './Constants.js' +import type { IntentStrings } from './Constants.js'; +import { Intents } from './Constants.js' import { CHANNEL, CHANNEL_BULK_DELETE, @@ -2381,7 +2382,7 @@ export interface ClientOptions { /** How many times to attempt resuming. */ maxResumeAttempts?: number /** The intents to use when connection to gateway. */ - intents?: GatewayIntents | number | (IntentStrings | number)[] + intents?: GatewayIntents | number | Array /** Whether or not to automatically reconnect to gateway. */ autoreconnect?: boolean /** diff --git a/packages/client/src/Constants.ts b/packages/client/src/Constants.ts index 969231d8e..2b442cfde 100644 --- a/packages/client/src/Constants.ts +++ b/packages/client/src/Constants.ts @@ -557,4 +557,5 @@ export const WebhookTypes = { APPLICATION: 3 }; -export type IntentStrings = keyof typeof Intents; \ No newline at end of file +export type IntentStrings = keyof typeof Intents; +export type PermissionClientStrings = keyof typeof Permissions; diff --git a/packages/client/src/Structures/Permission.ts b/packages/client/src/Structures/Permission.ts index 29fdf8404..bb751bb17 100644 --- a/packages/client/src/Structures/Permission.ts +++ b/packages/client/src/Structures/Permission.ts @@ -2,6 +2,7 @@ import { BitwisePermissionFlags } from '@discordeno/types' import { Base } from '../Base.js' import type { BigString } from '../Client.js' +import { PermissionClientStrings, Permissions } from '../Constants.js' export class Permission { allow: bigint @@ -36,13 +37,13 @@ export class Permission { } /** Check if this permission allows a specific permission */ - has(permission: bigint | keyof typeof BitwisePermissionFlags): boolean { + has(permission: bigint | PermissionClientStrings): boolean { if (this.isAdmin) return true if (typeof permission === 'bigint') { return (this.allow & permission) === permission } - return !!(this.allow & BigInt(BitwisePermissionFlags[permission])) + return !!(this.allow & Permissions[permission]) } toString() { diff --git a/packages/client/src/Structures/channels/Private.ts b/packages/client/src/Structures/channels/Private.ts index 1c15f3733..d110a5291 100644 --- a/packages/client/src/Structures/channels/Private.ts +++ b/packages/client/src/Structures/channels/Private.ts @@ -36,7 +36,7 @@ export class PrivateChannel extends Channel { } /** Create a message in a text channel */ - async createMessage(content: MessageContent, file: FileContent | FileContent[]): Promise { + async createMessage(content: MessageContent, file?: FileContent | FileContent[]): Promise { return await this.client.createMessage.call(this.client, this.id, content, file) } diff --git a/packages/client/src/Structures/channels/Text.ts b/packages/client/src/Structures/channels/Text.ts index 3152df0e5..50116c318 100644 --- a/packages/client/src/Structures/channels/Text.ts +++ b/packages/client/src/Structures/channels/Text.ts @@ -109,7 +109,7 @@ export class TextChannel extends GuildChannel { * @arg {String} file.name What to name the file * @returns {Promise} */ - async createMessage(content: MessageContent, file: FileContent | FileContent[]) { + async createMessage(content: MessageContent, file?: FileContent | FileContent[]) { return this.client.createMessage.call(this.client, this.id, content, file) } diff --git a/packages/client/src/Structures/guilds/Guild.ts b/packages/client/src/Structures/guilds/Guild.ts index 913798ca8..b79b3e11b 100644 --- a/packages/client/src/Structures/guilds/Guild.ts +++ b/packages/client/src/Structures/guilds/Guild.ts @@ -24,6 +24,7 @@ import type Client from '../../Client.js' import type { ImageFormat, ImageSize } from '../../Client.js' import Collection from '../../Collection.js' import { BANNER, GUILD_DISCOVERY_SPLASH, GUILD_ICON, GUILD_SPLASH } from '../../Endpoints.js' +import type Shard from '../../gateway/Shard.js' import type { AnyGuildChannel, AnyThreadChannel, @@ -185,10 +186,14 @@ export class Guild extends Base { voiceStates = new Collection() /** The cached stage instances in this guild. */ stageInstances = new Collection() + /** The shard that manages this guild. */ + shard: Shard; constructor(data: DiscordGuild, client: Client) { super(data.id) this.client = client + this.shard = client.shards.get(client.guildShardMap[this.id] || (Base.getDiscordEpoch(data.id) % (client.options.maxShards as number)) || 0)!; + this.ownerID = data.owner_id this.unavailable = !!data.unavailable diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index 814fae492..fcc4bcaac 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -47,3 +47,5 @@ export * from './Structures/users/User.js' export * from './typings.js' export * from './utils/BrowserWebSocket.js' export * from './utils/Bucket.js' +export * from './utils/DiscordRESTError.js' +export * from './utils/generate.js' diff --git a/packages/client/src/typings.ts b/packages/client/src/typings.ts index 278ef640b..7f7079f8c 100644 --- a/packages/client/src/typings.ts +++ b/packages/client/src/typings.ts @@ -37,6 +37,16 @@ import type GuildAuditLogEntry from './Structures/guilds/AuditLogEntry.js' import type GuildIntegration from './Structures/guilds/Integration.js' import type Member from './Structures/guilds/Member.js' import type User from './Structures/users/User.js' +import type { Guild, Invite } from './index.js' +import type Role from './Structures/guilds/Role.js' +import type StageInstance from './Structures/guilds/StageInstance.js' +import type UnavailableGuild from './Structures/guilds/Unavailable.js' +import type AutocompleteInteraction from './Structures/interactions/Autocomplete.js' +import type CommandInteraction from './Structures/interactions/Command.js' +import type ComponentInteraction from './Structures/interactions/Component.js' +import type PingInteraction from './Structures/interactions/Ping.js' +import type UnknownInteraction from './Structures/interactions/Unknown.js' +import type { IncomingHttpHeaders } from 'node:http' export type ApplicationCommandStructure = ChatInputApplicationCommandStructure | MessageApplicationCommandStructure | UserApplicationCommandStructure export type ChatInputApplicationCommand = ApplicationCommand @@ -885,3 +895,85 @@ export const MessageFlags = { EPHEMERAL: 64, LOADING: 128, } + +export interface EventListeners { + channelCreate: [channel: AnyGuildChannel]; + channelDelete: [channel: AnyChannel]; + channelPinUpdate: [channel: TextableChannel, timestamp: number, oldTimestamp: number]; + channelUpdate: [channel: AnyGuildChannel, oldChannel: any]; + connect: [id: number]; + debug: [message: string, id?: number]; + disconnect: []; + error: [err: Error, id?: number]; + guildAvailable: [guild: Guild]; + guildBanAdd: [guild: Guild, user: User]; + guildBanRemove: [guild: Guild, user: User]; + guildCreate: [guild: Guild]; + guildDelete: [guild: any]; + guildEmojisUpdate: [guild: any, emojis: Emoji[], oldEmojis: Emoji[] | null]; + guildMemberAdd: [guild: Guild, member: Member]; + guildMemberChunk: [guild: Guild, member: Member[]]; + guildMemberRemove: [guild: Guild, member: Member | any]; + guildMemberUpdate: [guild: Guild, member: Member, oldMember: any | null]; + guildRoleCreate: [guild: Guild, role: Role]; + guildRoleDelete: [guild: Guild, role: Role]; + guildRoleUpdate: [guild: Guild, role: Role, oldRole: any]; + guildScheduledEventCreate: [event: any]; + guildScheduledEventDelete: [event: any]; + guildScheduledEventUpdate: [event: any, oldEvent: any | null]; + guildScheduledEventUserAdd: [event: any, user: User | Uncached]; + guildScheduledEventUserRemove: [event: any, user: User | Uncached]; + guildStickersUpdate: [guild: any, stickers: Sticker[], oldStickers: Sticker[] | null]; + guildUnavailable: [guild: UnavailableGuild]; + guildUpdate: [guild: Guild, oldGuild: any]; + hello: [trace: string[], id: number]; + interactionCreate: [interaction: PingInteraction | CommandInteraction | ComponentInteraction | AutocompleteInteraction | UnknownInteraction]; + inviteCreate: [guild: Guild, invite: Invite]; + inviteDelete: [guild: Guild, invite: Invite]; + messageCreate: [message: Message]; + messageDelete: [message: any]; + messageDeleteBulk: [messages: any[]]; + messageReactionAdd: [message: any, emoji: PartialEmoji, reactor: Member | Uncached]; + messageReactionRemove: [message: any, emoji: PartialEmoji, userID: string]; + messageReactionRemoveAll: [message: any]; + messageReactionRemoveEmoji: [message: any, emoji: PartialEmoji]; + messageUpdate: [message: Message, oldMessage: any | null]; + presenceUpdate: [other: Member, oldPresence: any | null]; + rawREST: [request: any]; + rawWS: [packet: any, id: number]; + ready: []; + shardPreReady: [id: number]; + stageInstanceCreate: [stageInstance: StageInstance]; + stageInstanceDelete: [stageInstance: StageInstance]; + stageInstanceUpdate: [stageInstance: StageInstance, oldStageInstance: any | null]; + threadCreate: [channel: AnyThreadChannel]; + threadDelete: [channel: AnyThreadChannel]; + threadListSync: [guild: Guild, deletedThreads: Array, activeThreads: AnyThreadChannel[], joinedThreadsMember: ThreadMember[]]; + threadMembersUpdate: [channel: AnyThreadChannel, addedMembers: ThreadMember[], removedMembers: Array]; + threadMemberUpdate: [channel: AnyThreadChannel, member: ThreadMember, oldMember: any]; + threadUpdate: [channel: AnyThreadChannel, oldChannel: any | null]; + typingStart: [channel: GuildTextableChannel | Uncached, user: User | Uncached, member: Member] + | [channel: PrivateChannel | Uncached, user: User | Uncached, member: null]; + unavailableGuildCreate: [guild: UnavailableGuild]; + unknown: [packet: any, id?: number]; + userUpdate: [user: User, oldUser: PartialUser | null]; + voiceChannelJoin: [member: Member, channel: AnyVoiceChannel]; + voiceChannelLeave: [member: Member, channel: AnyVoiceChannel]; + voiceChannelSwitch: [member: Member, newChannel: AnyVoiceChannel, oldChannel: AnyVoiceChannel]; + voiceStateUpdate: [member: Member, oldState: any]; + warn: [message: string, id?: number]; + webhooksUpdate: [data: any]; +} + +export interface ClientEvents extends EventListeners { + shardDisconnect: [err: Error | undefined, id: number]; + shardReady: [id: number]; + shardResume: [id: number]; +} + +export interface HTTPResponse { + code: number; + message: string; + errors?: HTTPResponse + headers: IncomingHttpHeaders +} diff --git a/packages/client/src/utils/DiscordRESTError.ts b/packages/client/src/utils/DiscordRESTError.ts new file mode 100644 index 000000000..c93a5f75d --- /dev/null +++ b/packages/client/src/utils/DiscordRESTError.ts @@ -0,0 +1,86 @@ +import type { ClientRequest, IncomingHttpHeaders, IncomingMessage } from 'http' +import type { HTTPResponse } from '../typings.js' + +export class DiscordRESTError extends Error { + code: number = -1 + req!: ClientRequest + res!: IncomingMessage + response!: HTTPResponse + + constructor(req: ClientRequest, res: IncomingMessage, response: HTTPResponse, stack: string) { + super() + + Object.defineProperty(this, 'req', { + enumerable: false, + value: req, + }) + Object.defineProperty(this, 'res', { + enumerable: false, + value: res, + }) + Object.defineProperty(this, 'response', { + enumerable: false, + value: response, + }) + + Object.defineProperty(this, 'code', { + enumerable: false, + value: +response.code || -1, + }) + let message = response.message || 'Unknown error' + if (response.errors) { + message += '\n ' + this.flattenErrors(response.errors).join('\n ') + } else { + const errors = this.flattenErrors(response) + if (errors.length > 0) { + message += '\n ' + errors.join('\n ') + } + } + Object.defineProperty(this, 'message', { + enumerable: false, + value: message, + }) + + if (stack) { + this.stack = this.name + ': ' + this.message + '\n' + stack + } else { + Error.captureStackTrace(this, DiscordRESTError) + } + } + + get headers(): IncomingHttpHeaders { + return this.response.headers + } + + get name(): string { + return `${this.constructor.name} [${this.code}]` + } + + flattenErrors(errors: HTTPResponse, keyPrefix?: string): string[] { + let messages: string[] = [] + for (const fieldName of Object.keys(errors)) { + if (fieldName === 'message' || fieldName === 'code') { + continue + } + + const prefix = `${keyPrefix ?? ""}${fieldName}`; + + // @ts-expect-error js hack from eris + if (errors[fieldName]._errors) { + // @ts-expect-error js hack from eris + messages = messages.concat(errors[fieldName]._errors.map((obj: any) => `${prefix}: ${obj.message as string}`)) + // @ts-expect-error js hack from eris + } else if (Array.isArray(errors[fieldName])) { + // @ts-expect-error js hack from eris + messages = messages.concat(errors[fieldName].map((str: string) => `${prefix}: ${str}`)) + // @ts-expect-error js hack from eris + } else if (typeof errors[fieldName] === 'object') { + // @ts-expect-error js hack from eris + messages = messages.concat(this.flattenErrors(errors[fieldName], `${prefix}.`)) + } + } + return messages + } +} + +export default DiscordRESTError