diff --git a/packages/core/src/api/monetization.ts b/packages/core/src/api/monetization.ts index 12e7f5c66b83..8f181fc6fd93 100644 --- a/packages/core/src/api/monetization.ts +++ b/packages/core/src/api/monetization.ts @@ -77,4 +77,20 @@ export class MonetizationAPI { ) { await this.rest.delete(Routes.entitlement(applicationId, entitlementId), { signal }); } + + /** + * Marks a given entitlement for the user as consumed. Only available for One-Time Purchase consumable SKUs. + * + * @see {@link https://discord.com/developers/docs/monetization/entitlements#consume-an-entitlement} + * @param applicationId - The application id to consume the entitlement for + * @param entitlementId - The entitlement id to consume + * @param options - The options for consuming the entitlement + */ + public async consumeEntitlement( + applicationId: Snowflake, + entitlementId: Snowflake, + { signal }: Pick = {}, + ) { + await this.rest.post(Routes.consumeEntitlement(applicationId, entitlementId), { signal }); + } } diff --git a/packages/discord.js/src/managers/EntitlementManager.js b/packages/discord.js/src/managers/EntitlementManager.js index a392b05b93ca..1456d3719acb 100644 --- a/packages/discord.js/src/managers/EntitlementManager.js +++ b/packages/discord.js/src/managers/EntitlementManager.js @@ -124,6 +124,16 @@ class EntitlementManager extends CachedManager { await this.client.rest.delete(Routes.entitlement(this.client.application.id, resolved)); } + + /** + * Marks an entitlement as consumed + * Only available for One-Time Purchase consumable SKUs. + * @param {Snowflake} entitlementId The id of the entitlement to consume + * @returns {Promise} + */ + async consume(entitlementId) { + await this.client.rest.post(Routes.consumeEntitlement(this.client.application.id, entitlementId)); + } } exports.EntitlementManager = EntitlementManager; diff --git a/packages/discord.js/src/structures/Entitlement.js b/packages/discord.js/src/structures/Entitlement.js index 9560a97709d9..115873438cf0 100644 --- a/packages/discord.js/src/structures/Entitlement.js +++ b/packages/discord.js/src/structures/Entitlement.js @@ -91,6 +91,16 @@ class Entitlement extends Base { } else { this.endsTimestamp ??= null; } + + if ('consumed' in data) { + /** + * Whether this entitlement has been consumed + * @type {boolean} + */ + this.consumed = data.consumed; + } else { + this.consumed ??= false; + } } /** @@ -159,6 +169,15 @@ class Entitlement extends Base { fetchUser() { return this.client.users.fetch(this.userId); } + + /** + * Marks this entitlement as consumed + * Only available for One-Time Purchase consumable SKUs. + * @returns {Promise} + */ + async consume() { + await this.client.application.entitlements.consume(this.id); + } } exports.Entitlement = Entitlement; diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index f1a2d8b1cd0a..6723969f672a 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -1346,12 +1346,14 @@ export class Entitlement extends Base { public guildId: Snowflake | null; public applicationId: Snowflake; public type: EntitlementType; + public consumed: boolean; public deleted: boolean; public startsTimestamp: number | null; public endsTimestamp: number | null; public get guild(): Guild | null; public get startsAt(): Date | null; public get endsAt(): Date | null; + public consume(): Promise; public fetchUser(): Promise; public isActive(): boolean; public isTest(): this is this & { @@ -4179,6 +4181,7 @@ export class EntitlementManager extends CachedManager>; public createTest(options: GuildEntitlementCreateOptions | UserEntitlementCreateOptions): Promise; public deleteTest(entitlement: EntitlementResolvable): Promise; + public consume(entitlementId: Snowflake): Promise; } export interface FetchGuildApplicationCommandFetchOptions extends Omit {} diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index de82182fc7f6..ef44dca762f3 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -2495,6 +2495,8 @@ declare const sku: SKU; await application.entitlements.deleteTest(entitlement); + await application.entitlements.consume(snowflake); + expectType(entitlement.isActive()); if (entitlement.isUserSubscription()) {