mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-10 00:23:30 +01:00
feat: application emojis (#10399)
* feat: application emojis * chore: requested changes --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
@@ -2,10 +2,17 @@
|
||||
|
||||
import type { RequestData, REST } from '@discordjs/rest';
|
||||
import {
|
||||
Routes,
|
||||
type RESTGetAPIApplicationEmojiResult,
|
||||
type RESTGetAPIApplicationEmojisResult,
|
||||
type RESTGetCurrentApplicationResult,
|
||||
type RESTPatchAPIApplicationEmojiJSONBody,
|
||||
type RESTPatchAPIApplicationEmojiResult,
|
||||
type RESTPatchCurrentApplicationJSONBody,
|
||||
type RESTPatchCurrentApplicationResult,
|
||||
Routes,
|
||||
type RESTPostAPIApplicationEmojiJSONBody,
|
||||
type RESTPostAPIApplicationEmojiResult,
|
||||
type Snowflake,
|
||||
} from 'discord-api-types/v10';
|
||||
|
||||
export class ApplicationsAPI {
|
||||
@@ -34,4 +41,83 @@ export class ApplicationsAPI {
|
||||
signal,
|
||||
}) as Promise<RESTPatchCurrentApplicationResult>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all emojis of an application
|
||||
*
|
||||
* @see {@link https://discord.com/developers/docs/resources/emoji#list-application-emojis}
|
||||
* @param applicationId - The id of the application to fetch the emojis of
|
||||
* @param options - The options for fetching the emojis
|
||||
*/
|
||||
public async getEmojis(applicationId: Snowflake, { signal }: Pick<RequestData, 'signal'> = {}) {
|
||||
return this.rest.get(Routes.applicationEmojis(applicationId), {
|
||||
signal,
|
||||
}) as Promise<RESTGetAPIApplicationEmojisResult>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches an emoji of an application
|
||||
*
|
||||
* @see {@link https://discord.com/developers/docs/resources/emoji#get-application-emoji}
|
||||
* @param applicationId - The id of the application to fetch the emoji of
|
||||
* @param emojiId - The id of the emoji to fetch
|
||||
* @param options - The options for fetching the emoji
|
||||
*/
|
||||
public async getEmoji(applicationId: Snowflake, emojiId: Snowflake, { signal }: Pick<RequestData, 'signal'> = {}) {
|
||||
return this.rest.get(Routes.applicationEmoji(applicationId, emojiId), {
|
||||
signal,
|
||||
}) as Promise<RESTGetAPIApplicationEmojiResult>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new emoji of an application
|
||||
*
|
||||
* @see {@link https://discord.com/developers/docs/resources/emoji#create-application-emoji}
|
||||
* @param applicationId - The id of the application to create the emoji of
|
||||
* @param body - The data for creating the emoji
|
||||
* @param options - The options for creating the emoji
|
||||
*/
|
||||
public async createEmoji(
|
||||
applicationId: Snowflake,
|
||||
body: RESTPostAPIApplicationEmojiJSONBody,
|
||||
{ signal }: Pick<RequestData, 'signal'> = {},
|
||||
) {
|
||||
return this.rest.post(Routes.applicationEmojis(applicationId), {
|
||||
body,
|
||||
signal,
|
||||
}) as Promise<RESTPostAPIApplicationEmojiResult>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits an emoji of an application
|
||||
*
|
||||
* @see {@link https://discord.com/developers/docs/resources/emoji#modify-application-emoji}
|
||||
* @param applicationId - The id of the application to edit the emoji of
|
||||
* @param emojiId - The id of the emoji to edit
|
||||
* @param body - The data for editing the emoji
|
||||
* @param options - The options for editing the emoji
|
||||
*/
|
||||
public async editEmoji(
|
||||
applicationId: Snowflake,
|
||||
emojiId: Snowflake,
|
||||
body: RESTPatchAPIApplicationEmojiJSONBody,
|
||||
{ signal }: Pick<RequestData, 'signal'> = {},
|
||||
) {
|
||||
return this.rest.patch(Routes.applicationEmoji(applicationId, emojiId), {
|
||||
body,
|
||||
signal,
|
||||
}) as Promise<RESTPatchAPIApplicationEmojiResult>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an emoji of an application
|
||||
*
|
||||
* @see {@link https://discord.com/developers/docs/resources/emoji#delete-application-emoji}
|
||||
* @param applicationId - The id of the application to delete the emoji of
|
||||
* @param emojiId - The id of the emoji to delete
|
||||
* @param options - The options for deleting the emoji
|
||||
*/
|
||||
public async deleteEmoji(applicationId: Snowflake, emojiId: Snowflake, { signal }: Pick<RequestData, 'signal'> = {}) {
|
||||
await this.rest.delete(Routes.applicationEmoji(applicationId, emojiId), { signal });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ exports.version = require('../package.json').version;
|
||||
|
||||
// Managers
|
||||
exports.ApplicationCommandManager = require('./managers/ApplicationCommandManager');
|
||||
exports.ApplicationEmojiManager = require('./managers/ApplicationEmojiManager');
|
||||
exports.ApplicationCommandPermissionsManager = require('./managers/ApplicationCommandPermissionsManager');
|
||||
exports.AutoModerationRuleManager = require('./managers/AutoModerationRuleManager');
|
||||
exports.BaseGuildEmojiManager = require('./managers/BaseGuildEmojiManager');
|
||||
@@ -98,6 +99,7 @@ exports.Activity = require('./structures/Presence').Activity;
|
||||
exports.AnonymousGuild = require('./structures/AnonymousGuild');
|
||||
exports.Application = require('./structures/interfaces/Application');
|
||||
exports.ApplicationCommand = require('./structures/ApplicationCommand');
|
||||
exports.ApplicationEmoji = require('./structures/ApplicationEmoji');
|
||||
exports.ApplicationRoleConnectionMetadata =
|
||||
require('./structures/ApplicationRoleConnectionMetadata').ApplicationRoleConnectionMetadata;
|
||||
exports.AutocompleteInteraction = require('./structures/AutocompleteInteraction');
|
||||
|
||||
142
packages/discord.js/src/managers/ApplicationEmojiManager.js
Normal file
142
packages/discord.js/src/managers/ApplicationEmojiManager.js
Normal file
@@ -0,0 +1,142 @@
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const { Routes } = require('discord-api-types/v10');
|
||||
const CachedManager = require('./CachedManager');
|
||||
const { DiscordjsTypeError, ErrorCodes } = require('../errors');
|
||||
const ApplicationEmoji = require('../structures/ApplicationEmoji');
|
||||
const { resolveImage } = require('../util/DataResolver');
|
||||
|
||||
/**
|
||||
* Manages API methods for ApplicationEmojis and stores their cache.
|
||||
* @extends {CachedManager}
|
||||
*/
|
||||
class ApplicationEmojiManager extends CachedManager {
|
||||
constructor(application, iterable) {
|
||||
super(application.client, ApplicationEmoji, iterable);
|
||||
|
||||
/**
|
||||
* The application this manager belongs to
|
||||
* @type {ClientApplication}
|
||||
*/
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
_add(data, cache) {
|
||||
return super._add(data, cache, { extras: [this.application] });
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used for creating an emoji of the application
|
||||
* @typedef {Object} ApplicationEmojiCreateOptions
|
||||
* @property {BufferResolvable|Base64Resolvable} attachment The image for the emoji
|
||||
* @property {string} name The name for the emoji
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new custom emoji of the application.
|
||||
* @param {ApplicationEmojiCreateOptions} options Options for creating the emoji
|
||||
* @returns {Promise<Emoji>} The created emoji
|
||||
* @example
|
||||
* // Create a new emoji from a URL
|
||||
* application.emojis.create({ attachment: 'https://i.imgur.com/w3duR07.png', name: 'rip' })
|
||||
* .then(emoji => console.log(`Created new emoji with name ${emoji.name}!`))
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Create a new emoji from a file on your computer
|
||||
* application.emojis.create({ attachment: './memes/banana.png', name: 'banana' })
|
||||
* .then(emoji => console.log(`Created new emoji with name ${emoji.name}!`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async create({ attachment, name }) {
|
||||
attachment = await resolveImage(attachment);
|
||||
if (!attachment) throw new DiscordjsTypeError(ErrorCodes.ReqResourceType);
|
||||
|
||||
const body = { image: attachment, name };
|
||||
|
||||
const emoji = await this.client.rest.post(Routes.applicationEmojis(this.application.id), { body });
|
||||
return this._add(emoji);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains one or more emojis from Discord, or the emoji cache if they're already available.
|
||||
* @param {Snowflake} [id] The emoji's id
|
||||
* @param {BaseFetchOptions} [options] Additional options for this fetch
|
||||
* @returns {Promise<ApplicationEmoji|Collection<Snowflake, ApplicationEmoji>>}
|
||||
* @example
|
||||
* // Fetch all emojis from the application
|
||||
* message.application.emojis.fetch()
|
||||
* .then(emojis => console.log(`There are ${emojis.size} emojis.`))
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Fetch a single emoji
|
||||
* message.application.emojis.fetch('222078108977594368')
|
||||
* .then(emoji => console.log(`The emoji name is: ${emoji.name}`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async fetch(id, { cache = true, force = false } = {}) {
|
||||
if (id) {
|
||||
if (!force) {
|
||||
const existing = this.cache.get(id);
|
||||
if (existing) return existing;
|
||||
}
|
||||
const emoji = await this.client.rest.get(Routes.applicationEmoji(this.application.id, id));
|
||||
return this._add(emoji, cache);
|
||||
}
|
||||
|
||||
const { items: data } = await this.client.rest.get(Routes.applicationEmojis(this.application.id));
|
||||
const emojis = new Collection();
|
||||
for (const emoji of data) emojis.set(emoji.id, this._add(emoji, cache));
|
||||
return emojis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an emoji.
|
||||
* @param {EmojiResolvable} emoji The Emoji resolvable to delete
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async delete(emoji) {
|
||||
const id = this.resolveId(emoji);
|
||||
if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'emoji', 'EmojiResolvable', true);
|
||||
await this.client.rest.delete(Routes.applicationEmoji(this.application.id, id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits an emoji.
|
||||
* @param {EmojiResolvable} emoji The Emoji resolvable to edit
|
||||
* @param {ApplicationEmojiEditOptions} options The options to provide
|
||||
* @returns {Promise<ApplicationEmoji>}
|
||||
*/
|
||||
async edit(emoji, options) {
|
||||
const id = this.resolveId(emoji);
|
||||
if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'emoji', 'EmojiResolvable', true);
|
||||
|
||||
const newData = await this.client.rest.patch(Routes.applicationEmoji(this.application.id, id), {
|
||||
body: {
|
||||
name: options.name,
|
||||
},
|
||||
});
|
||||
const existing = this.cache.get(id);
|
||||
if (existing) {
|
||||
existing._patch(newData);
|
||||
return existing;
|
||||
}
|
||||
return this._add(newData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the author for this emoji
|
||||
* @param {EmojiResolvable} emoji The emoji to fetch the author of
|
||||
* @returns {Promise<User>}
|
||||
*/
|
||||
async fetchAuthor(emoji) {
|
||||
const id = this.resolveId(emoji);
|
||||
if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'emoji', 'EmojiResolvable', true);
|
||||
|
||||
const data = await this.client.rest.get(Routes.applicationEmoji(this.application.id, id));
|
||||
|
||||
return this._add(data).author;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ApplicationEmojiManager;
|
||||
118
packages/discord.js/src/structures/ApplicationEmoji.js
Normal file
118
packages/discord.js/src/structures/ApplicationEmoji.js
Normal file
@@ -0,0 +1,118 @@
|
||||
'use strict';
|
||||
|
||||
const { Emoji } = require('./Emoji');
|
||||
|
||||
/**
|
||||
* Represents a custom emoji.
|
||||
* @extends {Emoji}
|
||||
*/
|
||||
class ApplicationEmoji extends Emoji {
|
||||
constructor(client, data, application) {
|
||||
super(client, data);
|
||||
|
||||
/**
|
||||
* The application this emoji originates from
|
||||
* @type {ClientApplication}
|
||||
*/
|
||||
this.application = application;
|
||||
|
||||
/**
|
||||
* The user who created this emoji
|
||||
* @type {?User}
|
||||
*/
|
||||
this.author = null;
|
||||
|
||||
this.managed = null;
|
||||
this.requiresColons = null;
|
||||
|
||||
this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
if ('name' in data) this.name = data.name;
|
||||
if (data.user) this.author = this.client.users._add(data.user);
|
||||
|
||||
if ('managed' in data) {
|
||||
/**
|
||||
* Whether this emoji is managed by an external service
|
||||
* @type {?boolean}
|
||||
*/
|
||||
this.managed = data.managed;
|
||||
}
|
||||
|
||||
if ('require_colons' in data) {
|
||||
/**
|
||||
* Whether or not this emoji requires colons surrounding it
|
||||
* @type {?boolean}
|
||||
*/
|
||||
this.requiresColons = data.require_colons;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the author for this emoji
|
||||
* @returns {Promise<User>}
|
||||
*/
|
||||
fetchAuthor() {
|
||||
return this.application.emojis.fetchAuthor(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data for editing an emoji.
|
||||
* @typedef {Object} ApplicationEmojiEditOptions
|
||||
* @property {string} [name] The name of the emoji
|
||||
*/
|
||||
|
||||
/**
|
||||
* Edits the emoji.
|
||||
* @param {ApplicationEmojiEditOptions} options The options to provide
|
||||
* @returns {Promise<ApplicationEmoji>}
|
||||
* @example
|
||||
* // Edit an emoji
|
||||
* emoji.edit({ name: 'newemoji' })
|
||||
* .then(emoji => console.log(`Edited emoji ${emoji}`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
edit(options) {
|
||||
return this.application.emojis.edit(this.id, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the emoji.
|
||||
* @param {string} name The new name for the emoji
|
||||
* @returns {Promise<ApplicationEmoji>}
|
||||
*/
|
||||
setName(name) {
|
||||
return this.edit({ name });
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the emoji.
|
||||
* @returns {Promise<ApplicationEmoji>}
|
||||
*/
|
||||
async delete() {
|
||||
await this.application.emojis.delete(this.id);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this emoji is the same as another one.
|
||||
* @param {ApplicationEmoji|APIEmoji} other The emoji to compare it to
|
||||
* @returns {boolean}
|
||||
*/
|
||||
equals(other) {
|
||||
if (other instanceof ApplicationEmoji) {
|
||||
return (
|
||||
other.animated === this.animated &&
|
||||
other.id === this.id &&
|
||||
other.name === this.name &&
|
||||
other.managed === this.managed &&
|
||||
other.requiresColons === this.requiresColons
|
||||
);
|
||||
}
|
||||
|
||||
return other.id === this.id && other.name === this.name;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ApplicationEmoji;
|
||||
@@ -7,6 +7,7 @@ const { SKU } = require('./SKU');
|
||||
const Team = require('./Team');
|
||||
const Application = require('./interfaces/Application');
|
||||
const ApplicationCommandManager = require('../managers/ApplicationCommandManager');
|
||||
const ApplicationEmojiManager = require('../managers/ApplicationEmojiManager');
|
||||
const { EntitlementManager } = require('../managers/EntitlementManager');
|
||||
const ApplicationFlagsBitField = require('../util/ApplicationFlagsBitField');
|
||||
const { resolveImage } = require('../util/DataResolver');
|
||||
@@ -32,6 +33,12 @@ class ClientApplication extends Application {
|
||||
*/
|
||||
this.commands = new ApplicationCommandManager(this.client);
|
||||
|
||||
/**
|
||||
* The application emoji manager for this application
|
||||
* @type {ApplicationEmojiManager}
|
||||
*/
|
||||
this.emojis = new ApplicationEmojiManager(this);
|
||||
|
||||
/**
|
||||
* The entitlement manager for this application
|
||||
* @type {EntitlementManager}
|
||||
|
||||
@@ -8,7 +8,7 @@ const Base = require('./Base');
|
||||
let deprecationEmittedForURL = false;
|
||||
|
||||
/**
|
||||
* Represents an emoji, see {@link GuildEmoji} and {@link ReactionEmoji}.
|
||||
* Represents an emoji, see {@link ApplicationEmoji}, {@link GuildEmoji} and {@link ReactionEmoji}.
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Emoji extends Base {
|
||||
|
||||
37
packages/discord.js/typings/index.d.ts
vendored
37
packages/discord.js/typings/index.d.ts
vendored
@@ -191,6 +191,7 @@ import {
|
||||
RawAnonymousGuildData,
|
||||
RawApplicationCommandData,
|
||||
RawApplicationData,
|
||||
RawApplicationEmojiData,
|
||||
RawBaseGuildData,
|
||||
RawChannelData,
|
||||
RawClientApplicationData,
|
||||
@@ -1061,6 +1062,7 @@ export class ClientApplication extends Application {
|
||||
public botRequireCodeGrant: boolean | null;
|
||||
public bot: User | null;
|
||||
public commands: ApplicationCommandManager;
|
||||
public emojis: ApplicationEmojiManager;
|
||||
public entitlements: EntitlementManager;
|
||||
public guildId: Snowflake | null;
|
||||
public get guild(): Guild | null;
|
||||
@@ -1342,6 +1344,41 @@ export class Emoji extends Base {
|
||||
public toString(): string;
|
||||
}
|
||||
|
||||
export interface ApplicationEmojiCreateOptions {
|
||||
attachment: BufferResolvable | Base64Resolvable;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface ApplicationEmojiEditOptions {
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export class ApplicationEmoji extends Emoji {
|
||||
private constructor(client: Client<true>, data: RawApplicationEmojiData, application: ClientApplication);
|
||||
|
||||
public application: ClientApplication;
|
||||
public author: User | null;
|
||||
public id: Snowflake;
|
||||
public managed: boolean | null;
|
||||
public requiresColons: boolean | null;
|
||||
public delete(): Promise<ApplicationEmoji>;
|
||||
public edit(options: ApplicationEmojiEditOptions): Promise<ApplicationEmoji>;
|
||||
public equals(other: ApplicationEmoji | unknown): boolean;
|
||||
public fetchAuthor(): Promise<User>;
|
||||
public setName(name: string): Promise<ApplicationEmoji>;
|
||||
}
|
||||
|
||||
export class ApplicationEmojiManager extends CachedManager<Snowflake, ApplicationEmoji, EmojiResolvable> {
|
||||
private constructor(application: ClientApplication, iterable?: Iterable<RawApplicationEmojiData>);
|
||||
public application: ClientApplication;
|
||||
public create(options: ApplicationEmojiCreateOptions): Promise<ApplicationEmoji>;
|
||||
public fetch(id: Snowflake, options?: BaseFetchOptions): Promise<ApplicationEmoji>;
|
||||
public fetch(id?: undefined, options?: BaseFetchOptions): Promise<Collection<Snowflake, ApplicationEmoji>>;
|
||||
public fetchAuthor(emoji: EmojiResolvable): Promise<User>;
|
||||
public delete(emoji: EmojiResolvable): Promise<void>;
|
||||
public edit(emoji: EmojiResolvable, options: ApplicationEmojiEditOptions): Promise<ApplicationEmoji>;
|
||||
}
|
||||
|
||||
export class Entitlement extends Base {
|
||||
private constructor(client: Client<true>, data: APIEntitlement);
|
||||
public id: Snowflake;
|
||||
|
||||
@@ -206,6 +206,8 @@ import {
|
||||
ChannelSelectMenuComponent,
|
||||
MentionableSelectMenuComponent,
|
||||
Poll,
|
||||
ApplicationEmoji,
|
||||
ApplicationEmojiManager,
|
||||
} from '.';
|
||||
import { expectAssignable, expectDeprecated, expectNotAssignable, expectNotType, expectType } from 'tsd';
|
||||
import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders';
|
||||
@@ -1695,6 +1697,11 @@ expectType<Promise<Collection<Snowflake, GuildEmoji>>>(guildEmojiManager.fetch()
|
||||
expectType<Promise<Collection<Snowflake, GuildEmoji>>>(guildEmojiManager.fetch(undefined, {}));
|
||||
expectType<Promise<GuildEmoji>>(guildEmojiManager.fetch('0'));
|
||||
|
||||
declare const applicationEmojiManager: ApplicationEmojiManager;
|
||||
expectType<Promise<Collection<Snowflake, ApplicationEmoji>>>(applicationEmojiManager.fetch());
|
||||
expectType<Promise<Collection<Snowflake, ApplicationEmoji>>>(applicationEmojiManager.fetch(undefined, {}));
|
||||
expectType<Promise<ApplicationEmoji>>(applicationEmojiManager.fetch('0'));
|
||||
|
||||
declare const guildBanManager: GuildBanManager;
|
||||
{
|
||||
expectType<Promise<GuildBan>>(guildBanManager.fetch('1234567890'));
|
||||
|
||||
@@ -102,6 +102,7 @@ export type RawEmojiData =
|
||||
| RawReactionEmojiData
|
||||
| GatewayActivityEmoji
|
||||
| Omit<Partial<APIPartialEmoji>, 'animated'>;
|
||||
export type RawApplicationEmojiData = APIEmoji;
|
||||
export type RawGuildEmojiData = APIEmoji;
|
||||
export type RawReactionEmojiData = APIEmoji | APIPartialEmoji;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user