feat: add support for User Apps

#1183 #1198
This commit is contained in:
Elysia
2024-07-03 22:40:40 +07:00
parent 485dab55bf
commit ecb870b324
4 changed files with 67 additions and 2 deletions

View File

@@ -721,6 +721,51 @@ class Client extends BaseClient {
}); });
} }
/**
* Install User Apps
* @param {Snowflake} applicationId Discord Application id
* @returns {Promise<void>}
*/
installUserApps(applicationId) {
return this.api
.applications(applicationId)
.public.get({
query: {
with_guild: false,
},
})
.then(rawData => {
const installTypes = rawData.integration_types_config['1'];
if (installTypes) {
return this.api.oauth2.authorize.post({
query: {
client_id: applicationId,
scope: installTypes.oauth2_install_params.scopes.join(' '),
},
data: {
permissions: '0',
authorize: true,
integration_type: 1,
},
});
} else {
return false;
}
});
}
/**
* Deauthorize an application.
* @param {Snowflake} applicationId Discord Application id
* @returns {Promise<void>}
*/
deauthorize(applicationId) {
return this.api.oauth2.tokens
.get()
.then(data => data.find(o => o.application.id == applicationId))
.then(o => this.api.oauth2.tokens(o.id).delete());
}
/** /**
* Calls {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval} on a script * Calls {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval} on a script
* with the client as `this`. * with the client as `this`.

View File

@@ -169,6 +169,7 @@ const Messages = {
// Selfbot // Selfbot
INVALID_USER_API: 'User accounts cannot use this endpoint', INVALID_USER_API: 'User accounts cannot use this endpoint',
INVALID_APPLICATION_COMMAND: id => `Could not find a valid command for this bot: ${id}`,
INVALID_COMMAND_NAME: allCMD => `Could not parse subGroupCommand and subCommand due to too long: ${allCMD.join(' ')}`, INVALID_COMMAND_NAME: allCMD => `Could not parse subGroupCommand and subCommand due to too long: ${allCMD.join(' ')}`,
INVALID_SLASH_COMMAND_CHOICES: (parentOptions, value) => INVALID_SLASH_COMMAND_CHOICES: (parentOptions, value) =>
`${value} is not a valid choice for this option (${parentOptions})`, `${value} is not a valid choice for this option (${parentOptions})`,

View File

@@ -187,7 +187,7 @@ class TextBasedChannel {
return this.messages.cache.get(d.id) ?? this.messages._add(d); return this.messages.cache.get(d.id) ?? this.messages._add(d);
} }
searchInteraction() { searchInteractionFromGuildAndPrivateChannel() {
// Support Slash / ContextMenu // Support Slash / ContextMenu
// API https://canary.discord.com/api/v9/guilds/:id/application-command-index // Guild // API https://canary.discord.com/api/v9/guilds/:id/application-command-index // Guild
// https://canary.discord.com/api/v9/channels/:id/application-command-index // DM Channel // https://canary.discord.com/api/v9/channels/:id/application-command-index // DM Channel
@@ -197,6 +197,19 @@ class TextBasedChannel {
].get(); ].get();
} }
searchInteractionUserApps() {
return this.client.api.users['@me']['application-command-index'].get();
}
searchInteraction() {
return Promise.all([this.searchInteractionFromGuildAndPrivateChannel(), this.searchInteractionUserApps()]).then(
([dataA, dataB]) => ({
applications: [...dataA.applications, ...dataB.applications],
application_commands: [...dataA.application_commands, ...dataB.application_commands],
}),
);
}
async sendSlash(botOrApplicationId, commandNameString, ...args) { async sendSlash(botOrApplicationId, commandNameString, ...args) {
// Parse commandName /role add user // Parse commandName /role add user
const cmd = commandNameString.trim().split(' '); const cmd = commandNameString.trim().split(' ');
@@ -226,7 +239,9 @@ class TextBasedChannel {
); );
// Find Command with application // Find Command with application
const command = filterCommand.find(command => command.application_id == application.id); const command = filterCommand.find(command => command.application_id == application.id);
if (!command) {
throw new Error('INVALID_APPLICATION_COMMAND', application.id);
}
args = args.flat(2); args = args.flat(2);
let optionFormat = []; let optionFormat = [];
let attachments = []; let attachments = [];
@@ -472,6 +487,8 @@ class TextBasedChannel {
props.push( props.push(
'sendSlash', 'sendSlash',
'searchInteraction', 'searchInteraction',
'searchInteractionFromGuildAndPrivateChannel',
'searchInteractionUserApps',
'lastMessage', 'lastMessage',
'lastPinAt', 'lastPinAt',
'sendTyping', 'sendTyping',

2
typings/index.d.ts vendored
View File

@@ -785,6 +785,8 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
): Promise<Guild | DMChannel | GroupDMChannel>; ): Promise<Guild | DMChannel | GroupDMChannel>;
public redeemNitro(nitro: string, channel?: TextChannelResolvable, paymentSourceId?: Snowflake): Promise<any>; public redeemNitro(nitro: string, channel?: TextChannelResolvable, paymentSourceId?: Snowflake): Promise<any>;
public authorizeURL(url: string, options?: OAuth2AuthorizeOptions): Promise<any>; public authorizeURL(url: string, options?: OAuth2AuthorizeOptions): Promise<any>;
public installUserApps(applicationId: Snowflake): Promise<void>;
public deauthorize(applicationId: Snowflake): Promise<void>;
public on<K extends keyof ClientEvents>(event: K, listener: (...args: ClientEvents[K]) => Awaitable<void>): this; public on<K extends keyof ClientEvents>(event: K, listener: (...args: ClientEvents[K]) => Awaitable<void>): this;
public on<S extends string | symbol>( public on<S extends string | symbol>(