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
This commit is contained in:
Skillz4Killz
2023-02-27 23:08:09 -06:00
committed by GitHub
parent e48b9a16c6
commit cf121a870e
9 changed files with 195 additions and 7 deletions

View File

@@ -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<IntentStrings | number>
/** Whether or not to automatically reconnect to gateway. */
autoreconnect?: boolean
/**

View File

@@ -557,4 +557,5 @@ export const WebhookTypes = {
APPLICATION: 3
};
export type IntentStrings = keyof typeof Intents;
export type IntentStrings = keyof typeof Intents;
export type PermissionClientStrings = keyof typeof Permissions;

View File

@@ -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() {

View File

@@ -36,7 +36,7 @@ export class PrivateChannel extends Channel {
}
/** Create a message in a text channel */
async createMessage(content: MessageContent, file: FileContent | FileContent[]): Promise<Message> {
async createMessage(content: MessageContent, file?: FileContent | FileContent[]): Promise<Message> {
return await this.client.createMessage.call(this.client, this.id, content, file)
}

View File

@@ -109,7 +109,7 @@ export class TextChannel extends GuildChannel {
* @arg {String} file.name What to name the file
* @returns {Promise<Message>}
*/
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)
}

View File

@@ -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<BigString, VoiceState>()
/** The cached stage instances in this guild. */
stageInstances = new Collection<BigString, StageInstance>()
/** 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

View File

@@ -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'

View File

@@ -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<ApplicationCommandTypes.ChatInput>
@@ -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<AnyThreadChannel | Uncached>, activeThreads: AnyThreadChannel[], joinedThreadsMember: ThreadMember[]];
threadMembersUpdate: [channel: AnyThreadChannel, addedMembers: ThreadMember[], removedMembers: Array<ThreadMember | Uncached>];
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
}

View File

@@ -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