feat: premium application subscriptions (#9907)

* feat: premium application subscriptions

* types: readonly array

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>

* fix: requested changes

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>

* fix: core client types

---------

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
Almeida
2023-12-24 15:49:58 +00:00
committed by GitHub
parent 520d6f64dd
commit c4fcee3ef6
33 changed files with 914 additions and 10 deletions

View File

@@ -170,6 +170,11 @@ import {
TeamMemberRole,
GuildWidgetStyle,
GuildOnboardingMode,
APISKU,
SKUFlags,
SKUType,
APIEntitlement,
EntitlementType,
} from 'discord-api-types/v10';
import { ChildProcess } from 'node:child_process';
import { EventEmitter } from 'node:events';
@@ -585,6 +590,7 @@ export abstract class CommandInteraction<Cached extends CacheType = CacheType> e
| ModalComponentData
| APIModalInteractionResponseCallbackData,
): Promise<void>;
public sendPremiumRequired(): Promise<void>;
public awaitModalSubmit(
options: AwaitModalSubmitOptions<ModalSubmitInteraction>,
): Promise<ModalSubmitInteraction<Cached>>;
@@ -1033,6 +1039,7 @@ export class ClientApplication extends Application {
public botRequireCodeGrant: boolean | null;
public bot: User | null;
public commands: ApplicationCommandManager;
public entitlements: EntitlementManager;
public guildId: Snowflake | null;
public get guild(): Guild | null;
public cover: string | null;
@@ -1049,6 +1056,7 @@ export class ClientApplication extends Application {
public edit(options: ClientApplicationEditOptions): Promise<ClientApplication>;
public fetch(): Promise<ClientApplication>;
public fetchRoleConnectionMetadataRecords(): Promise<ApplicationRoleConnectionMetadata[]>;
public fetchSKUs(): Promise<Collection<Snowflake, SKU>>;
public editRoleConnectionMetadataRecords(
records: ApplicationRoleConnectionMetadataEditOptions[],
): Promise<ApplicationRoleConnectionMetadata[]>;
@@ -1305,6 +1313,32 @@ export class Emoji extends Base {
public toString(): string;
}
export class Entitlement extends Base {
private constructor(client: Client<true>, data: APIEntitlement);
public id: Snowflake;
public skuId: Snowflake;
public userId: Snowflake;
public guildId: Snowflake | null;
public applicationId: Snowflake;
public type: EntitlementType;
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 fetchUser(): Promise<User>;
public isActive(): boolean;
public isTest(): this is this & {
startsTimestamp: null;
endsTimestamp: null;
get startsAt(): null;
get endsAt(): null;
};
public isUserSubscription(): this is this & { guildId: null; get guild(): null };
public isGuildSubscription(): this is this & { guildId: Snowflake; guild: Guild };
}
export class Guild extends AnonymousGuild {
private constructor(client: Client<true>, data: RawGuildData);
private _sortedRoles(): Collection<Snowflake, Role>;
@@ -1829,6 +1863,7 @@ export class BaseInteraction<Cached extends CacheType = CacheType> extends Base
public memberPermissions: CacheTypeReducer<Cached, Readonly<PermissionsBitField>>;
public locale: Locale;
public guildLocale: CacheTypeReducer<Cached, Locale>;
public entitlements: Collection<Snowflake, Entitlement>;
public inGuild(): this is BaseInteraction<'raw' | 'cached'>;
public inCachedGuild(): this is BaseInteraction<'cached'>;
public inRawGuild(): this is BaseInteraction<'raw'>;
@@ -2178,6 +2213,7 @@ export class MessageComponentInteraction<Cached extends CacheType = CacheType> e
| ModalComponentData
| APIModalInteractionResponseCallbackData,
): Promise<void>;
public sendPremiumRequired(): Promise<void>;
public awaitModalSubmit(
options: AwaitModalSubmitOptions<ModalSubmitInteraction>,
): Promise<ModalSubmitInteraction<Cached>>;
@@ -2376,6 +2412,7 @@ export class ModalSubmitInteraction<Cached extends CacheType = CacheType> extend
options: InteractionDeferUpdateOptions & { fetchReply: true },
): Promise<Message<BooleanCache<Cached>>>;
public deferUpdate(options?: InteractionDeferUpdateOptions): Promise<InteractionResponse<BooleanCache<Cached>>>;
public sendPremiumRequired(): Promise<void>;
public inGuild(): this is ModalSubmitInteraction<'raw' | 'cached'>;
public inCachedGuild(): this is ModalSubmitInteraction<'cached'>;
public inRawGuild(): this is ModalSubmitInteraction<'raw'>;
@@ -2875,6 +2912,23 @@ export {
DeconstructedSnowflake,
} from '@sapphire/snowflake';
export class SKU extends Base {
private constructor(client: Client<true>, data: APISKU);
public id: Snowflake;
public type: SKUType;
public applicationId: Snowflake;
public name: string;
public slug: string;
public flags: Readonly<SKUFlagsBitField>;
}
export type SKUFlagsString = keyof typeof SKUFlags;
export class SKUFlagsBitField extends BitField<SKUFlagsString> {
public static FLAGS: typeof SKUFlags;
public static resolve(bit?: BitFieldResolvable<SKUFlagsString, number>): number;
}
export class StageChannel extends BaseGuildVoiceChannel {
public get stageInstance(): StageInstance | null;
public topic: string | null;
@@ -2974,6 +3028,9 @@ export class Sweepers {
public sweepEmojis(
filter: CollectionSweepFilter<SweeperDefinitions['emojis'][0], SweeperDefinitions['emojis'][1]>,
): number;
public sweepEntitlements(
filter: CollectionSweepFilter<SweeperDefinitions['entitlements'][0], SweeperDefinitions['entitlements'][1]>,
): number;
public sweepInvites(
filter: CollectionSweepFilter<SweeperDefinitions['invites'][0], SweeperDefinitions['invites'][1]>,
): number;
@@ -3281,6 +3338,7 @@ export function transformResolved<Cached extends CacheType>(
supportingData: SupportingInteractionResolvedData,
data?: APIApplicationCommandInteractionData['resolved'],
): CommandInteractionResolvedData<Cached>;
export function resolveSKUId(resolvable: SKUResolvable): Snowflake | null;
export interface MappedComponentBuilderTypes {
[ComponentType.Button]: ButtonBuilder;
@@ -3819,6 +3877,8 @@ export enum DiscordjsErrorCodes {
SweepFilterReturn = 'SweepFilterReturn',
GuildForumMessageRequired = 'GuildForumMessageRequired',
EntitlementCreateInvalidOwner = 'EntitlementCreateInvalidOwner',
}
/** @internal */
@@ -4002,6 +4062,37 @@ export class ChannelManager extends CachedManager<Snowflake, Channel, ChannelRes
public fetch(id: Snowflake, options?: FetchChannelOptions): Promise<Channel | null>;
}
export type EntitlementResolvable = Snowflake | Entitlement;
export type SKUResolvable = Snowflake | SKU;
export interface GuildEntitlementCreateOptions {
sku: SKUResolvable;
guild: GuildResolvable;
}
export interface UserEntitlementCreateOptions {
sku: SKUResolvable;
user: UserResolvable;
}
export interface FetchEntitlementsOptions {
limit?: number;
guild?: GuildResolvable;
user?: UserResolvable;
skus?: readonly SKUResolvable[];
excludeEnded?: boolean;
cache?: boolean;
before?: Snowflake;
after?: Snowflake;
}
export class EntitlementManager extends CachedManager<Snowflake, Entitlement, EntitlementResolvable> {
private constructor(client: Client<true>, iterable: Iterable<APIEntitlement>);
public fetch(options?: FetchEntitlementsOptions): Promise<Collection<Snowflake, Entitlement>>;
public createTest(options: GuildEntitlementCreateOptions | UserEntitlementCreateOptions): Promise<Entitlement>;
public deleteTest(entitlement: EntitlementResolvable): Promise<void>;
}
export interface FetchGuildApplicationCommandFetchOptions extends Omit<FetchApplicationCommandOptions, 'guildId'> {}
export class GuildApplicationCommandManager extends ApplicationCommandManager<ApplicationCommand, {}, Guild> {
@@ -4980,6 +5071,9 @@ export interface ClientEvents {
emojiCreate: [emoji: GuildEmoji];
emojiDelete: [emoji: GuildEmoji];
emojiUpdate: [oldEmoji: GuildEmoji, newEmoji: GuildEmoji];
entitlementCreate: [entitlement: Entitlement];
entitlementDelete: [entitlement: Entitlement];
entitlementUpdate: [oldEntitlement: Entitlement | null, newEntitlement: Entitlement];
error: [error: Error];
guildAuditLogEntryCreate: [auditLogEntry: GuildAuditLogsEntry, guild: Guild];
guildAvailable: [guild: Guild];
@@ -5192,6 +5286,9 @@ export enum Events {
AutoModerationRuleDelete = 'autoModerationRuleDelete',
AutoModerationRuleUpdate = 'autoModerationRuleUpdate',
ClientReady = 'ready',
EntitlementCreate = 'entitlementCreate',
EntitlementDelete = 'entitlementDelete',
EntitlementUpdate = 'entitlementUpdate',
GuildAuditLogEntryCreate = 'guildAuditLogEntryCreate',
GuildAvailable = 'guildAvailable',
GuildCreate = 'guildCreate',
@@ -6475,6 +6572,7 @@ export interface SweeperDefinitions {
autoModerationRules: [Snowflake, AutoModerationRule];
bans: [Snowflake, GuildBan];
emojis: [Snowflake, GuildEmoji];
entitlements: [Snowflake, Entitlement];
invites: [string, Invite, true];
guildMembers: [Snowflake, GuildMember];
messages: [Snowflake, Message, true];

View File

@@ -188,6 +188,8 @@ import {
Awaitable,
Channel,
DirectoryChannel,
Entitlement,
SKU,
} from '.';
import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd';
import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders';
@@ -2426,3 +2428,55 @@ declare const emoji: Emoji;
expectType<PartialEmojiOnlyId>(resolvePartialEmoji('12345678901234567'));
expectType<PartialEmoji | null>(resolvePartialEmoji(emoji));
}
declare const application: ClientApplication;
declare const entitlement: Entitlement;
declare const sku: SKU;
{
expectType<Collection<Snowflake, SKU>>(await application.fetchSKUs());
expectType<Collection<Snowflake, Entitlement>>(await application.entitlements.fetch());
await application.entitlements.fetch({
guild,
skus: ['12345678901234567', sku],
user,
excludeEnded: true,
limit: 10,
});
await application.entitlements.createTest({ sku: '12345678901234567', user });
await application.entitlements.createTest({ sku, guild });
await application.entitlements.deleteTest(entitlement);
expectType<boolean>(entitlement.isActive());
if (entitlement.isUserSubscription()) {
expectType<Snowflake>(entitlement.userId);
expectType<User>(await entitlement.fetchUser());
expectType<null>(entitlement.guildId);
expectType<null>(entitlement.guild);
await application.entitlements.deleteTest(entitlement);
} else if (entitlement.isGuildSubscription()) {
expectType<Snowflake>(entitlement.guildId);
expectType<Guild>(entitlement.guild);
await application.entitlements.deleteTest(entitlement);
}
if (entitlement.isTest()) {
expectType<null>(entitlement.startsTimestamp);
expectType<null>(entitlement.endsTimestamp);
expectType<null>(entitlement.startsAt);
expectType<null>(entitlement.endsAt);
}
client.on(Events.InteractionCreate, async interaction => {
expectType<Collection<Snowflake, Entitlement>>(interaction.entitlements);
if (interaction.isRepliable()) {
await interaction.sendPremiumRequired();
}
});
}