feat(TextChannel): add searchInteraction
This commit is contained in:
parent
91ae4195a6
commit
a6459f2c14
@ -47,17 +47,6 @@ await message.contextMenu(botID, commandName);
|
|||||||
```
|
```
|
||||||
</details>
|
</details>
|
||||||
<details open>
|
<details open>
|
||||||
<summary>Issue ?</summary>
|
|
||||||
|
|
||||||
- It has some minor bugs.
|
|
||||||
```js
|
|
||||||
DiscordAPIError [20012] You are not authorized to perform this action on this application
|
|
||||||
Fix it: creating 1 DMs with bot
|
|
||||||
In this way, all Slash commands can be obtained
|
|
||||||
```
|
|
||||||
- With Gateway guild.searchInteraction() (using gateway)
|
|
||||||
- With REST: Working ! [TextBasedChannel.sendSlash()].
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## MessageEmbed ?
|
## MessageEmbed ?
|
||||||
- Because Discord has removed the ability to send Embeds in its API, that means MessageEmbed is unusable. But I have created a constructor that uses oEmbed with help [from this site](https://www.reddit.com/r/discordapp/comments/82p8i6/a_basic_tutorial_on_how_to_get_the_most_out_of/)
|
- Because Discord has removed the ability to send Embeds in its API, that means MessageEmbed is unusable. But I have created a constructor that uses oEmbed with help [from this site](https://www.reddit.com/r/discordapp/comments/82p8i6/a_basic_tutorial_on_how_to_get_the_most_out_of/)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# Slash command demo
|
# Slash command demo
|
||||||
- Support Autocomplete feature (half)
|
- Support Autocomplete feature (half)
|
||||||
- Unused `guild.searchInteraction()` (Use only if not working properly)
|
- Unused `guild.searchInteraction()` (Deleted)
|
||||||
|
|
||||||
# <strong>BREAKING CHANGE: Using Slash Command (Sub Command / Sub Group Command) will not accept subCommand argument in args. That means Command Name needs to be changed same as Discord Client</strong>
|
# <strong>BREAKING CHANGE: Using Slash Command (Sub Command / Sub Group Command) will not accept subCommand argument in args. That means Command Name needs to be changed same as Discord Client</strong>
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ module.exports = (client, { d: data }) => {
|
|||||||
client.emit('interactionResponse', {
|
client.emit('interactionResponse', {
|
||||||
status: false,
|
status: false,
|
||||||
metadata: data,
|
metadata: data,
|
||||||
|
error: 'No response from bot',
|
||||||
});
|
});
|
||||||
// Delete cache
|
// Delete cache
|
||||||
client._interactionCache.delete(data.nonce);
|
client._interactionCache.delete(data.nonce);
|
||||||
|
@ -23,6 +23,7 @@ module.exports = (client, { d: data }) => {
|
|||||||
client.emit('interactionResponse', {
|
client.emit('interactionResponse', {
|
||||||
status: true,
|
status: true,
|
||||||
metadata: data_,
|
metadata: data_,
|
||||||
|
error: '',
|
||||||
});
|
});
|
||||||
// Delete cache
|
// Delete cache
|
||||||
// client._interactionCache.delete(data.nonce);
|
// client._interactionCache.delete(data.nonce);
|
||||||
|
@ -873,8 +873,15 @@ class ApplicationCommand extends Base {
|
|||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
this.client.removeListener('interactionResponse', handler);
|
this.client.removeListener('interactionResponse', handler);
|
||||||
this.client.decrementMaxListeners();
|
this.client.decrementMaxListeners();
|
||||||
if (data.status) resolve(data.metadata);
|
if (data.status) {
|
||||||
else reject(data.metadata);
|
resolve(data.metadata);
|
||||||
|
} else {
|
||||||
|
reject(
|
||||||
|
new Error('INTERACTION_ERROR', {
|
||||||
|
cause: data,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
this.client.removeListener('interactionResponse', handler);
|
this.client.removeListener('interactionResponse', handler);
|
||||||
@ -958,8 +965,15 @@ class ApplicationCommand extends Base {
|
|||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
this.client.removeListener('interactionResponse', handler);
|
this.client.removeListener('interactionResponse', handler);
|
||||||
this.client.decrementMaxListeners();
|
this.client.decrementMaxListeners();
|
||||||
if (data.status) resolve(data.metadata);
|
if (data.status) {
|
||||||
else reject(data.metadata);
|
resolve(data.metadata);
|
||||||
|
} else {
|
||||||
|
reject(
|
||||||
|
new Error('INTERACTION_ERROR', {
|
||||||
|
cause: data,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
this.client.removeListener('interactionResponse', handler);
|
this.client.removeListener('interactionResponse', handler);
|
||||||
|
@ -185,6 +185,7 @@ class BaseGuildTextChannel extends GuildChannel {
|
|||||||
setRateLimitPerUser() {}
|
setRateLimitPerUser() {}
|
||||||
setNSFW() {}
|
setNSFW() {}
|
||||||
sendSlash() {}
|
sendSlash() {}
|
||||||
|
searchInteraction() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextBasedChannel.applyToClass(BaseGuildTextChannel, true);
|
TextBasedChannel.applyToClass(BaseGuildTextChannel, true);
|
||||||
|
@ -149,6 +149,7 @@ class DMChannel extends Channel {
|
|||||||
createMessageComponentCollector() {}
|
createMessageComponentCollector() {}
|
||||||
awaitMessageComponent() {}
|
awaitMessageComponent() {}
|
||||||
sendSlash() {}
|
sendSlash() {}
|
||||||
|
searchInteraction() {}
|
||||||
// Doesn't work on DM channels; bulkDelete() {}
|
// Doesn't work on DM channels; bulkDelete() {}
|
||||||
// Doesn't work on DM channels; setRateLimitPerUser() {}
|
// Doesn't work on DM channels; setRateLimitPerUser() {}
|
||||||
// Doesn't work on DM channels; setNSFW() {}
|
// Doesn't work on DM channels; setNSFW() {}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const process = require('node:process');
|
const process = require('node:process');
|
||||||
const setTimeout = require('node:timers').setTimeout;
|
|
||||||
const { Collection } = require('@discordjs/collection');
|
const { Collection } = require('@discordjs/collection');
|
||||||
const AnonymousGuild = require('./AnonymousGuild');
|
const AnonymousGuild = require('./AnonymousGuild');
|
||||||
const GuildAuditLogs = require('./GuildAuditLogs');
|
const GuildAuditLogs = require('./GuildAuditLogs');
|
||||||
@ -32,12 +31,8 @@ const {
|
|||||||
Status,
|
Status,
|
||||||
MFALevels,
|
MFALevels,
|
||||||
PremiumTiers,
|
PremiumTiers,
|
||||||
Opcodes,
|
|
||||||
Events,
|
|
||||||
ApplicationCommandTypes,
|
|
||||||
} = require('../util/Constants');
|
} = require('../util/Constants');
|
||||||
const DataResolver = require('../util/DataResolver');
|
const DataResolver = require('../util/DataResolver');
|
||||||
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
|
||||||
const SystemChannelFlags = require('../util/SystemChannelFlags');
|
const SystemChannelFlags = require('../util/SystemChannelFlags');
|
||||||
const Util = require('../util/Util');
|
const Util = require('../util/Util');
|
||||||
|
|
||||||
@ -625,67 +620,6 @@ class Guild extends AnonymousGuild {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Options for guildSearchInteraction
|
|
||||||
* @typedef {Object} GuildSearchInteractionOptions
|
|
||||||
* @property {string} query Command name
|
|
||||||
* @property {?number} [limit=10] Maximum number of results
|
|
||||||
* @property {?number} [offset=0] Only return entries for actions made by this user
|
|
||||||
* @property {?Snowflake} [botId] BotID
|
|
||||||
* @property {?ApplicationCommandType} [type=CHAT_INPUT] Type of command
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Searches for guild interactions
|
|
||||||
* @param {GuildSearchInteractionOptions} options Options for the search
|
|
||||||
* @deprecated
|
|
||||||
* @returns {void | Promise<ApplicationCommand>}
|
|
||||||
*/
|
|
||||||
searchInteraction(options = {}) {
|
|
||||||
let { query, limit, offset, botId, type } = Object.assign(
|
|
||||||
{ query: undefined, limit: 10, offset: 0, botId: undefined, type: 'CHAT_INPUT' },
|
|
||||||
options,
|
|
||||||
);
|
|
||||||
if (!query) throw new Error('MISSING_VALUE', 'searchInteraction', 'query');
|
|
||||||
const nonce = SnowflakeUtil.generate();
|
|
||||||
this.shard.send({
|
|
||||||
op: Opcodes.REQUEST_APPLICATION_COMMANDS,
|
|
||||||
d: {
|
|
||||||
guild_id: this.id,
|
|
||||||
applications: false,
|
|
||||||
limit,
|
|
||||||
offset,
|
|
||||||
query,
|
|
||||||
nonce,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!botId || !type) return undefined;
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const handler = applications => {
|
|
||||||
timeout.refresh();
|
|
||||||
if (applications.nonce !== nonce) return;
|
|
||||||
const cmd = applications.application_commands.find(app => app.name == query && app.application_id == botId);
|
|
||||||
if (!cmd) return;
|
|
||||||
clearTimeout(timeout);
|
|
||||||
this.client.removeListener(Events.GUILD_APPLICATION_COMMANDS_UPDATE, handler);
|
|
||||||
this.client.decrementMaxListeners();
|
|
||||||
resolve(
|
|
||||||
this.client.users.cache
|
|
||||||
.get(botId)
|
|
||||||
?.application?.commands?.cache?.find(
|
|
||||||
c => (c.name === query && c.type == type) || c.type == ApplicationCommandTypes[type],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
this.client.removeListener(Events.GUILD_APPLICATION_COMMANDS_UPDATE, handler);
|
|
||||||
this.client.decrementMaxListeners();
|
|
||||||
reject(new Error('GUILD_APPLICATION_COMMANDS_SEARCH_TIMEOUT'));
|
|
||||||
}, 10000).unref();
|
|
||||||
this.client.incrementMaxListeners();
|
|
||||||
this.client.on(Events.GUILD_APPLICATION_COMMANDS_UPDATE, handler);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches a collection of integrations to this guild.
|
* Fetches a collection of integrations to this guild.
|
||||||
* Resolves with a collection mapping integrations by their ids.
|
* Resolves with a collection mapping integrations by their ids.
|
||||||
|
@ -203,8 +203,15 @@ class MessageButton extends BaseMessageComponent {
|
|||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
message.client.removeListener('interactionResponse', handler);
|
message.client.removeListener('interactionResponse', handler);
|
||||||
message.client.decrementMaxListeners();
|
message.client.decrementMaxListeners();
|
||||||
if (data.status) resolve(data.metadata);
|
if (data.status) {
|
||||||
else reject(data.metadata);
|
resolve(data.metadata);
|
||||||
|
} else {
|
||||||
|
reject(
|
||||||
|
new Error('INTERACTION_ERROR', {
|
||||||
|
cause: data,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
message.client.removeListener('interactionResponse', handler);
|
message.client.removeListener('interactionResponse', handler);
|
||||||
|
@ -273,8 +273,15 @@ class MessageSelectMenu extends BaseMessageComponent {
|
|||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
message.client.removeListener('interactionResponse', handler);
|
message.client.removeListener('interactionResponse', handler);
|
||||||
message.client.decrementMaxListeners();
|
message.client.decrementMaxListeners();
|
||||||
if (data.status) resolve(data.metadata);
|
if (data.status) {
|
||||||
else reject(data.metadata);
|
resolve(data.metadata);
|
||||||
|
} else {
|
||||||
|
reject(
|
||||||
|
new Error('INTERACTION_ERROR', {
|
||||||
|
cause: data,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
message.client.removeListener('interactionResponse', handler);
|
message.client.removeListener('interactionResponse', handler);
|
||||||
|
@ -407,6 +407,34 @@ class TextBasedChannel {
|
|||||||
return this.edit({ nsfw }, reason);
|
return this.edit({ nsfw }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search Slash Command (return raw data)
|
||||||
|
* @param {Snowflake} applicationId Application ID
|
||||||
|
* @param {?ApplicationCommandType} type Command Type
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
searchInteraction(applicationId, type = 'CHAT_INPUT') {
|
||||||
|
switch (type) {
|
||||||
|
case 'USER':
|
||||||
|
case 2:
|
||||||
|
type = 2;
|
||||||
|
break;
|
||||||
|
case 'MESSAGE':
|
||||||
|
case 3:
|
||||||
|
type = 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
type = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return this.client.api.channels[this.id]['application-commands'].search.get({
|
||||||
|
query: {
|
||||||
|
type,
|
||||||
|
application_id: applicationId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send Slash to this channel
|
* Send Slash to this channel
|
||||||
* @param {UserResolvable} bot Bot user
|
* @param {UserResolvable} bot Bot user
|
||||||
@ -459,15 +487,7 @@ class TextBasedChannel {
|
|||||||
}
|
}
|
||||||
if (user._partial) await user.getProfile().catch(() => {});
|
if (user._partial) await user.getProfile().catch(() => {});
|
||||||
if (!commandName || typeof commandName !== 'string') throw new Error('Command name is required');
|
if (!commandName || typeof commandName !== 'string') throw new Error('Command name is required');
|
||||||
// Using API to search (without opcode ~ehehe)
|
const data = await this.searchInteraction(user.application?.id ?? user.id, 'CHAT_INPUT');
|
||||||
// https://discord.com/api/v9/channels/id/application-commands/search?type=1&application_id=161660517914509312
|
|
||||||
const query = {
|
|
||||||
type: 1, // Slash commands
|
|
||||||
application_id: user.application?.id ?? user.id,
|
|
||||||
};
|
|
||||||
const data = await this.client.api.channels[this.id]['application-commands'].search.get({
|
|
||||||
query,
|
|
||||||
});
|
|
||||||
for (const command of data.application_commands) {
|
for (const command of data.application_commands) {
|
||||||
if (user.id == command.application_id || user.application.id == command.application_id) {
|
if (user.id == command.application_id || user.application.id == command.application_id) {
|
||||||
user.application?.commands?._add(command, true);
|
user.application?.commands?._add(command, true);
|
||||||
@ -515,6 +535,7 @@ class TextBasedChannel {
|
|||||||
'setRateLimitPerUser',
|
'setRateLimitPerUser',
|
||||||
'setNSFW',
|
'setNSFW',
|
||||||
'sendSlash',
|
'sendSlash',
|
||||||
|
'searchInteraction',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for (const prop of props) {
|
for (const prop of props) {
|
||||||
|
14
typings/index.d.ts
vendored
14
typings/index.d.ts
vendored
@ -1300,7 +1300,6 @@ export class Guild extends AnonymousGuild {
|
|||||||
public fetchAuditLogs<T extends GuildAuditLogsResolvable = 'ALL'>(
|
public fetchAuditLogs<T extends GuildAuditLogsResolvable = 'ALL'>(
|
||||||
options?: GuildAuditLogsFetchOptions<T>,
|
options?: GuildAuditLogsFetchOptions<T>,
|
||||||
): Promise<GuildAuditLogs<T>>;
|
): Promise<GuildAuditLogs<T>>;
|
||||||
public searchInteraction(options?: guildSearchInteraction): Promise<Collection<Snowflake, ApplicationCommand>>;
|
|
||||||
public fetchIntegrations(): Promise<Collection<Snowflake | string, Integration>>;
|
public fetchIntegrations(): Promise<Collection<Snowflake | string, Integration>>;
|
||||||
public fetchOwner(options?: BaseFetchOptions): Promise<GuildMember>;
|
public fetchOwner(options?: BaseFetchOptions): Promise<GuildMember>;
|
||||||
public fetchPreview(): Promise<GuildPreview>;
|
public fetchPreview(): Promise<GuildPreview>;
|
||||||
@ -4132,6 +4131,10 @@ export interface TextBasedChannelFields extends PartialTextBasedChannelFields {
|
|||||||
fetchWebhooks(): Promise<Collection<Snowflake, Webhook>>;
|
fetchWebhooks(): Promise<Collection<Snowflake, Webhook>>;
|
||||||
sendTyping(): Promise<void>;
|
sendTyping(): Promise<void>;
|
||||||
sendSlash(bot: UserResolvable, commandName: string, ...args: any): Promise<InteractionResponse>;
|
sendSlash(bot: UserResolvable, commandName: string, ...args: any): Promise<InteractionResponse>;
|
||||||
|
searchInteraction(
|
||||||
|
applicationId: ApplicationCommandTypes,
|
||||||
|
type?: ApplicationCommandTypes,
|
||||||
|
): Promise<Object>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PartialWebhookMixin<T>(Base?: Constructable<T>): Constructable<T & PartialWebhookFields>;
|
export function PartialWebhookMixin<T>(Base?: Constructable<T>): Constructable<T & PartialWebhookFields>;
|
||||||
@ -4379,15 +4382,6 @@ export interface ApplicationAsset {
|
|||||||
type: 'BIG' | 'SMALL';
|
type: 'BIG' | 'SMALL';
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy
|
|
||||||
export interface guildSearchInteraction {
|
|
||||||
type?: ApplicationCommandTypes;
|
|
||||||
query?: string | null | undefined;
|
|
||||||
limit?: number;
|
|
||||||
offset?: number;
|
|
||||||
botID?: Snowflake;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ClientEvents extends BaseClientEvents {
|
export interface ClientEvents extends BaseClientEvents {
|
||||||
/** @deprecated See [this issue](https://github.com/discord/discord-api-docs/issues/3690) for more information. */
|
/** @deprecated See [this issue](https://github.com/discord/discord-api-docs/issues/3690) for more information. */
|
||||||
applicationCommandCreate: [command: ApplicationCommand];
|
applicationCommandCreate: [command: ApplicationCommand];
|
||||||
|
Loading…
Reference in New Issue
Block a user