Skip to content

Commit

Permalink
fix(discord): fix slash command 403 and 429
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Aug 20, 2023
1 parent 448b849 commit 0802652
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 20 deletions.
24 changes: 11 additions & 13 deletions adapters/discord/src/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,39 +204,37 @@ export class DiscordBot extends Bot<DiscordBot.Config> {
const remote = Object.fromEntries((await this.internal.getGlobalApplicationCommands(this.selfId, { with_localizations: true }))
.filter(cmd => cmd.type === Discord.ApplicationCommand.Type.CHAT_INPUT)
.map(cmd => [cmd.name, cmd] as const))

const updates: any[] = []
for (const key in { ...local, ...remote }) {
if (!local[key]) {
logger.debug('delete command %s', key)
await this.internal.deleteGlobalApplicationCommand(this.selfId, remote[key].id)
continue
}

const data = Discord.encodeCommand(local[key])
logger.debug(data, remote[key])
if (!remote[key]) {
logger.debug('create command: %s', local[key].name)
await this.internal.createGlobalApplicationCommand(this.selfId, data)
updates.push(data)
} else if (!shapeEqual(data, remote[key])) {
logger.debug('edit command: %s', local[key].name)
await this.internal.editGlobalApplicationCommand(this.selfId, remote[key].id, data)
updates.push(data)
}
}
if (updates.length) {
await this.internal.bulkOverwriteGlobalApplicationCommands(this.selfId, updates)
}
}
}

function shapeEqual(a: any, b: any, strict = false) {
function shapeEqual(a: any, b: any) {
if (a === b) return true
if (strict && isNullable(a) && isNullable(b)) return true
if (!strict && !a && !b) return true
// ^ a.required = false, b.required = undefined
if (isNullable(a) && isNullable(b)) return true

if (typeof a !== typeof b) return false
if (typeof a !== 'object') return false
if ((typeof a === 'object' && Object.values(a).every(v => !v) && !b)
|| (typeof b === 'object' && Object.values(b).every(v => !v) && !a)) return true
// ^ one is object with undefined values, other is undefined (*_localizations)
// a = { foo: undefined }, b = undefined
if (Object.values(a).every(isNullable) && isNullable(b)) return true
// ^ a = { foo: undefined }, b = null
if (!a || !b) return false

// check array
Expand All @@ -248,7 +246,7 @@ function shapeEqual(a: any, b: any, strict = false) {
}

// check object
return Object.keys(a).every(key => shapeEqual(a[key], b[key], strict))
return Object.keys(a).every(key => shapeEqual(a[key], b[key]))
}

export namespace DiscordBot {
Expand Down
2 changes: 1 addition & 1 deletion adapters/discord/src/types/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ declare module './internal' {
* Takes a list of application commands, overwriting the existing global command list for this application. Updates will be available in all guilds after 1 hour. Returns 200 and a list of application command objects. Commands that do not already exist will count toward daily application command create limits.
* @see https://discord.com/developers/docs/interactions/application-commands#bulk-overwrite-global-application-commands
*/
bulkOverwriteGlobalApplicationCommands(application_id: snowflake): Promise<ApplicationCommand[]>
bulkOverwriteGlobalApplicationCommands(application_id: snowflake, data: ApplicationCommand.Params.Create[]): Promise<ApplicationCommand[]>
/**
* Fetch a global command for your application. Returns an application command object.
* @see https://discord.com/developers/docs/interactions/application-commands#get-global-application-command
Expand Down
12 changes: 6 additions & 6 deletions adapters/discord/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,12 @@ export async function adaptSession(bot: DiscordBot, input: Discord.Gateway.Paylo
if (input.t === 'MESSAGE_CREATE') {
setupMessageGuildId(session, input.d.guild_id)
if (input.d.webhook_id && !session.isDirect) {
const webhook = await bot.ensureWebhook(input.d.channel_id)
if (webhook.id === input.d.webhook_id) {
try {
// 403 Missing Permissions
const webhook = await bot.ensureWebhook(input.d.channel_id)
// koishi's webhook
return
}
if (webhook.id === input.d.webhook_id) return
} catch (e) {}
}
session.type = 'message'
await decodeMessage(bot, input.d, session)
Expand Down Expand Up @@ -291,14 +292,14 @@ export function encodeCommandOptions(cmd: Universal.Command): Discord.Applicatio
description_localizations: pick(cmd.description, Discord.Locale),
})))
} else {
// `getGlobalApplicationCommands()` does not return `required` property.
for (const arg of cmd.arguments) {
result.push({
name: arg.name.toLowerCase().replace(/[^a-z0-9]/g, ''),
description: arg.description[''] || arg.name,
description_localizations: pick(arg.description, Discord.Locale),
type: types[arg.type] ?? types.text,
// required: arg.required ?? false,
required: false,
})
}
for (const option of cmd.options) {
Expand All @@ -308,7 +309,6 @@ export function encodeCommandOptions(cmd: Universal.Command): Discord.Applicatio
description_localizations: pick(option.description, Discord.Locale),
type: types[option.type] ?? types.text,
// required: option.required ?? false,
required: false,
min_value: option.type === 'posint' ? 1 : undefined,
})
}
Expand Down

0 comments on commit 0802652

Please sign in to comment.