From 47d0cea66429e3507a8bfff1691c14c2aa40adc7 Mon Sep 17 00:00:00 2001 From: Fleny Date: Sun, 26 May 2024 20:38:48 +0200 Subject: [PATCH] feat(bot,rest,types): Add support for one-time entitlements (#3626) * Add support for one-time entitlements * Add comment to consumeEntitlement route Co-authored-by: LTS20050703 * Check for undefined instead of falsy values in consumed for entitlements Co-authored-by: LTS20050703 --------- Co-authored-by: LTS20050703 Co-authored-by: Awesome Stickz --- packages/bot/src/transformers.ts | 2 ++ packages/bot/src/transformers/entitlement.ts | 3 +++ packages/rest/src/manager.ts | 6 +++++- packages/rest/src/routes.ts | 3 +++ packages/rest/src/types.ts | 6 +++++- packages/rest/src/typings/routes.ts | 2 ++ packages/types/src/discord.ts | 20 ++++++++++++++++++++ 7 files changed, 40 insertions(+), 2 deletions(-) diff --git a/packages/bot/src/transformers.ts b/packages/bot/src/transformers.ts index 1ed622f9e..20f9b7f35 100644 --- a/packages/bot/src/transformers.ts +++ b/packages/bot/src/transformers.ts @@ -520,6 +520,7 @@ export interface Transformers { deleted: boolean startsAt: boolean endsAt: boolean + consumed: boolean } sku: { id: boolean @@ -1127,6 +1128,7 @@ export function createTransformers(options: Partial, opts?: Create deleted: opts?.defaultDesiredPropertiesValue ?? false, startsAt: opts?.defaultDesiredPropertiesValue ?? false, endsAt: opts?.defaultDesiredPropertiesValue ?? false, + consumed: opts?.defaultDesiredPropertiesValue ?? false, }, sku: { id: opts?.defaultDesiredPropertiesValue ?? false, diff --git a/packages/bot/src/transformers/entitlement.ts b/packages/bot/src/transformers/entitlement.ts index 6c0c0d2a9..cf8a6d857 100644 --- a/packages/bot/src/transformers/entitlement.ts +++ b/packages/bot/src/transformers/entitlement.ts @@ -14,6 +14,7 @@ export function transformEntitlement(bot: Bot, payload: DiscordEntitlement): Ent if (props.deleted && payload.deleted) entitlement.deleted = payload.deleted if (props.startsAt && payload.starts_at) entitlement.startsAt = Date.parse(payload.starts_at) if (props.endsAt && payload.ends_at) entitlement.endsAt = Date.parse(payload.ends_at) + if (props.consumed && payload.consumed !== undefined) entitlement.consumed = payload.consumed return bot.transformers.customizers.entitlement(bot, payload, entitlement) } @@ -37,4 +38,6 @@ export interface Entitlement { startsAt?: number /** Date at which the entitlement is no longer valid. Not present when using test entitlements */ endsAt?: number + /** For consumable items, whether or not the entitlement has been consumed */ + consumed?: boolean } diff --git a/packages/rest/src/manager.ts b/packages/rest/src/manager.ts index 8fa55ed82..5589686b4 100644 --- a/packages/rest/src/manager.ts +++ b/packages/rest/src/manager.ts @@ -24,6 +24,7 @@ import { type DiscordEmoji, type DiscordEntitlement, type DiscordFollowedChannel, + type DiscordGetAnswerVotesResponse, type DiscordGetGatewayBot, type DiscordGuild, type DiscordGuildApplicationCommandPermissions, @@ -40,7 +41,6 @@ import { type DiscordMemberWithUser, type DiscordMessage, type DiscordPartialGuild, - type DiscordGetAnswerVotesResponse, type DiscordPrunedCount, type DiscordRole, type DiscordScheduledEvent, @@ -1495,6 +1495,10 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage await rest.delete(rest.routes.monetization.entitlement(applicationId, entitlementId)) }, + async consumeEntitlement(applicationId, entitlementId) { + await rest.post(rest.routes.monetization.consumeEntitlement(applicationId, entitlementId)) + }, + async listSkus(applicationId) { return await rest.get(rest.routes.monetization.skus(applicationId)) }, diff --git a/packages/rest/src/routes.ts b/packages/rest/src/routes.ts index 23a5b23ae..e5283c240 100644 --- a/packages/rest/src/routes.ts +++ b/packages/rest/src/routes.ts @@ -617,6 +617,9 @@ export function createRoutes(): RestRoutes { entitlement: (applicationId, entitlementId) => { return `/applications/${applicationId}/entitlements/${entitlementId}` }, + consumeEntitlement: (applicationId, entitlementId) => { + return `/applications/${applicationId}/entitlements/${entitlementId}/consume` + }, skus: (applicationId) => { return `/applications/${applicationId}/skus` diff --git a/packages/rest/src/types.ts b/packages/rest/src/types.ts index 167378f39..9fadd7685 100644 --- a/packages/rest/src/types.ts +++ b/packages/rest/src/types.ts @@ -21,6 +21,7 @@ import type { CamelizedDiscordEmoji, CamelizedDiscordEntitlement, CamelizedDiscordFollowedChannel, + CamelizedDiscordGetAnswerVotesResponse, CamelizedDiscordGetGatewayBot, CamelizedDiscordGuild, CamelizedDiscordGuildApplicationCommandPermissions, @@ -36,7 +37,6 @@ import type { CamelizedDiscordMessage, CamelizedDiscordModifyGuildWelcomeScreen, CamelizedDiscordPartialGuild, - CamelizedDiscordGetAnswerVotesResponse, CamelizedDiscordPrunedCount, CamelizedDiscordRole, CamelizedDiscordScheduledEvent, @@ -2903,6 +2903,10 @@ export interface RestManager { * @param entitlementId - The id of the entitlement to delete */ deleteTestEntitlement: (applicationId: BigString, entitlementId: BigString) => Promise + /** + * For One-Time Purchase consumable SKUs, marks a given entitlement for the user as consumed. The entitlement will have `consumed: true` when using {@link RestManager.listEntitlements | List Entitlements} + */ + consumeEntitlement: (applicationId: BigString, entitlementId: BigString) => Promise /** * Returns all SKUs for a given application * diff --git a/packages/rest/src/typings/routes.ts b/packages/rest/src/typings/routes.ts index d637c8929..c392cd51c 100644 --- a/packages/rest/src/typings/routes.ts +++ b/packages/rest/src/typings/routes.ts @@ -268,6 +268,8 @@ export interface RestRoutes { entitlements: (applicationId: BigString, options?: GetEntitlements) => string /** Route to delete an entitlement */ entitlement: (applicationId: BigString, entitlementId: BigString) => string + /** Route to consume an entitlement */ + consumeEntitlement: (applicationId: BigString, entitlementId: BigString) => string /** Route to list the SKUs */ skus: (applicationId: BigString) => string } diff --git a/packages/types/src/discord.ts b/packages/types/src/discord.ts index 818e53799..d3983008d 100644 --- a/packages/types/src/discord.ts +++ b/packages/types/src/discord.ts @@ -3265,10 +3265,26 @@ export interface DiscordEntitlement { starts_at?: string /** Date at which the entitlement is no longer valid. Not present when using test entitlements */ ends_at?: string + /** For consumable items, whether or not the entitlement has been consumed */ + consumed?: boolean } /** https://discord.com/developers/docs/monetization/entitlements#entitlement-object-entitlement-types */ export enum DiscordEntitlementType { + /** Entitlement was purchased by user */ + Purchase = 1, + /** Entitlement for Discord Nitro subscription */ + PremiumSubscription = 2, + /** Entitlement was gifted by developer */ + DeveloperGift = 3, + /** Entitlement was purchased by a dev in application test mode */ + TestModePurchase = 4, + /** Entitlement was granted when the SKU was free */ + FreePurchase = 5, + /** Entitlement was gifted by another user */ + UserGift = 6, + /** Entitlement was claimed by user for free as a Nitro Subscriber */ + PremiumPurchase = 7, /** Entitlement was purchased as an app subscription */ ApplicationSubscription = 8, } @@ -3291,6 +3307,10 @@ export interface DiscordSku { /** https://discord.com/developers/docs/monetization/skus#sku-object-sku-types */ export enum DiscordSkuType { + /** Durable one-time purchase */ + Durable = 2, + /** Consumable one-time purchase */ + Consumable = 3, /** Represents a recurring subscription */ Subscription = 5, /** System-generated group for each SUBSCRIPTION SKU created */