'use strict'; const process = require('node:process'); const { ApplicationFlags } = require('../../util/ApplicationFlags'); const { ClientApplicationAssetTypes, Endpoints } = require('../../util/Constants'); const Permissions = require('../../util/Permissions'); const SnowflakeUtil = require('../../util/SnowflakeUtil'); const { ApplicationRoleConnectionMetadata } = require('../ApplicationRoleConnectionMetadata'); const Base = require('../Base'); const Team = require('../Team'); const AssetTypes = Object.keys(ClientApplicationAssetTypes); let deprecationEmittedForFetchAssets = false; /** * Represents an OAuth2 Application. * @extends {Base} * @abstract */ class Application extends Base { constructor(client, data) { super(client); this._patch(data); } _patch(data) { /** * The application's id * @type {Snowflake} */ this.id = data.id; if ('name' in data) { /** * The name of the application * @type {?string} */ this.name = data.name; } else { this.name ??= null; } if ('description' in data) { /** * The application's description * @type {?string} */ this.description = data.description; } else { this.description ??= null; } if ('icon' in data) { /** * The application's icon hash * @type {?string} */ this.icon = data.icon; } else { this.icon ??= null; } if ('role_connections_verification_url' in data) { /** * This application's role connection verification entry point URL * @type {?string} */ this.roleConnectionsVerificationURL = data.role_connections_verification_url; } else { this.roleConnectionsVerificationURL ??= null; } // ClientApplication /** * The tags this application has (max of 5) * @type {string[]} */ this.tags = data.tags ?? []; if ('install_params' in data) { /** * Settings for this application's default in-app authorization * @type {?ClientApplicationInstallParams} */ this.installParams = { scopes: data.install_params.scopes, permissions: new Permissions(data.install_params.permissions).freeze(), }; } else { this.installParams ??= null; } if ('custom_install_url' in data) { /** * This application's custom installation URL * @type {?string} */ this.customInstallURL = data.custom_install_url; } else { this.customInstallURL = null; } if ('flags' in data) { /** * The flags this application has * @type {ApplicationFlags} */ this.flags = new ApplicationFlags(data.flags).freeze(); } if ('approximate_guild_count' in data) { /** * An approximate amount of guilds this application is in. * @type {?number} */ this.approximateGuildCount = data.approximate_guild_count; } else { this.approximateGuildCount ??= null; } if ('guild_id' in data) { /** * The id of the guild associated with this application. * @type {?Snowflake} */ this.guildId = data.guild_id; } else { this.guildId ??= null; } if ('cover_image' in data) { /** * The hash of the application's cover image * @type {?string} */ this.cover = data.cover_image; } else { this.cover ??= null; } if ('rpc_origins' in data) { /** * The application's RPC origins, if enabled * @type {string[]} */ this.rpcOrigins = data.rpc_origins; } else { this.rpcOrigins ??= []; } if ('bot_require_code_grant' in data) { /** * If this application's bot requires a code grant when using the OAuth2 flow * @type {?boolean} */ this.botRequireCodeGrant = data.bot_require_code_grant; } else { this.botRequireCodeGrant ??= null; } if ('bot_public' in data) { /** * If this application's bot is public * @type {?boolean} */ this.botPublic = data.bot_public; } else { this.botPublic ??= null; } /** * The owner of this OAuth application * @type {?(User|Team)} */ this.owner = data.team ? new Team(this.client, data.team) : data.owner ? this.client.users._add(data.owner) : this.owner ?? null; } /** * The guild associated with this application. * @type {?Guild} * @readonly */ get guild() { return this.client.guilds.cache.get(this.guildId) ?? null; } /** * Whether this application is partial * @type {boolean} * @readonly */ get partial() { return !this.name; } /** * The timestamp the application was created at * @type {number} * @readonly */ get createdTimestamp() { return SnowflakeUtil.timestampFrom(this.id); } /** * The time the application was created at * @type {Date} * @readonly */ get createdAt() { return new Date(this.createdTimestamp); } /** * Obtains this application from Discord. * @returns {Promise} */ async fetch() { const app = await this.client.api.oauth2.authorize.get({ query: { client_id: this.id, scope: 'bot applications.commands', }, }); const user = this.client.users._add(app.bot); user._partial = false; this._patch(app.application); return this; } /** * Gets this application's role connection metadata records * @returns {Promise} */ async fetchRoleConnectionMetadataRecords() { const metadata = await this.client.api.applications(this.id)('role-connections').metadata.get(); return metadata.map(data => new ApplicationRoleConnectionMetadata(data)); } /** * A link to the application's icon. * @param {StaticImageURLOptions} [options={}] Options for the Image URL * @returns {?string} */ iconURL({ format, size } = {}) { if (!this.icon) return null; return this.client.rest.cdn.AppIcon(this.id, this.icon, { format, size }); } /** * A link to this application's cover image. * @param {StaticImageURLOptions} [options={}] Options for the Image URL * @returns {?string} */ coverURL({ format, size } = {}) { if (!this.cover) return null; return Endpoints.CDN(this.client.options.http.cdn).AppIcon(this.id, this.cover, { format, size }); } /** * Asset data. * @typedef {Object} ApplicationAsset * @property {Snowflake} id The asset's id * @property {string} name The asset's name * @property {string} type The asset's type */ /** * Gets the application's rich presence assets. * @returns {Promise>} * @deprecated This will be removed in the next major as it is unsupported functionality. */ async fetchAssets() { if (!deprecationEmittedForFetchAssets) { process.emitWarning( 'Application#fetchAssets is deprecated as it is unsupported and will be removed in the next major version.', 'DeprecationWarning', ); deprecationEmittedForFetchAssets = true; } const assets = await this.client.api.oauth2.applications(this.id).assets.get(); return assets.map(a => ({ id: a.id, name: a.name, type: AssetTypes[a.type - 1], })); } /** * When concatenated with a string, this automatically returns the application's name instead of the * Application object. * @returns {?string} * @example * // Logs: Application name: My App * console.log(`Application name: ${application}`); */ toString() { return this.name; } toJSON() { return super.toJSON({ createdTimestamp: true }); } } module.exports = Application;