diff --git a/packages/api-types/src/common.ts b/packages/api-types/src/common.ts index 401b75e..3a1d836 100644 --- a/packages/api-types/src/common.ts +++ b/packages/api-types/src/common.ts @@ -79,6 +79,14 @@ export enum MessageComponentTypes { SelectMenu = 3, /** A text input object */ InputText = 4, + /** A select menu for picking from users */ + UserSelect = 5, + /** A select menu for picking from roles */ + RoleSelect = 6, + /** A select menu for picking from users and roles */ + MentionableSelect = 7, + /** A select menu for picking from channels */ + ChannelSelect = 8 } export enum TextStyles { @@ -1260,20 +1268,20 @@ export type MakeRequired = T & { [P in K]-?: T[P] }; // THANK YOU YUI FOR SHARING THIS! export type CamelCase = S extends `${infer P1}_${infer P2}${infer P3}` - ? `${Lowercase}${Uppercase}${CamelCase}` - : Lowercase; + ? `${Lowercase}${Uppercase}${CamelCase}` + : Lowercase; export type Camelize = { // eslint-disable-next-line @typescript-eslint/array-type [K in keyof T as CamelCase]: T[K] extends Array - ? // eslint-disable-next-line @typescript-eslint/ban-types - U extends {} - ? // eslint-disable-next-line @typescript-eslint/array-type - Array> - : T[K] - : // eslint-disable-next-line @typescript-eslint/ban-types - T[K] extends {} - ? Camelize - : never; + ? // eslint-disable-next-line @typescript-eslint/ban-types + U extends {} + ? // eslint-disable-next-line @typescript-eslint/array-type + Array> + : T[K] + : // eslint-disable-next-line @typescript-eslint/ban-types + T[K] extends {} + ? Camelize + : never; }; export type PickPartial = { diff --git a/packages/api-types/src/v10/index.ts b/packages/api-types/src/v10/index.ts index dff8bca..06addd7 100644 --- a/packages/api-types/src/v10/index.ts +++ b/packages/api-types/src/v10/index.ts @@ -1187,7 +1187,11 @@ export interface DiscordActionRow { } export interface DiscordSelectMenuComponent { - type: MessageComponentTypes.SelectMenu; + type: MessageComponentTypes.SelectMenu | + MessageComponentTypes.RoleSelect | + MessageComponentTypes.UserSelect | + MessageComponentTypes.MentionableSelect | + MessageComponentTypes.ChannelSelect; /** A custom identifier for this component. Maximum 100 characters. */ custom_id: string; /** A custom placeholder text if nothing is selected. Maximum 150 characters. */ @@ -2396,8 +2400,8 @@ export interface DiscordGuildMemberUpdate { /** https://discord.com/developers/docs/topics/gateway#message-reaction-remove-all */ export interface DiscordMessageReactionRemoveAll extends Pick< - DiscordMessageReactionAdd, - 'channel_id' | 'message_id' | 'guild_id' + DiscordMessageReactionAdd, + 'channel_id' | 'message_id' | 'guild_id' > { } // TODO: add docs link diff --git a/packages/core/src/structures/components.ts b/packages/core/src/structures/components.ts index 12bb62a..f3346d6 100644 --- a/packages/core/src/structures/components.ts +++ b/packages/core/src/structures/components.ts @@ -223,6 +223,10 @@ export class ActionRow extends BaseComponent implements ActionRowComponent { } return new Button(session, component); case MessageComponentTypes.SelectMenu: + case MessageComponentTypes.RoleSelect: + case MessageComponentTypes.UserSelect: + case MessageComponentTypes.MentionableSelect: + case MessageComponentTypes.ChannelSelect: return new SelectMenu(session, component); case MessageComponentTypes.InputText: return new TextInput( @@ -257,6 +261,10 @@ export class ComponentFactory { } return new Button(session, component); case MessageComponentTypes.SelectMenu: + case MessageComponentTypes.RoleSelect: + case MessageComponentTypes.UserSelect: + case MessageComponentTypes.MentionableSelect: + case MessageComponentTypes.ChannelSelect: return new SelectMenu(session, component); case MessageComponentTypes.InputText: return new TextInput( diff --git a/packages/helpers/src/builders/components/MessageSelectMenuBuilder.ts b/packages/helpers/src/builders/components/MessageSelectMenuBuilder.ts index 7556fa3..b691446 100644 --- a/packages/helpers/src/builders/components/MessageSelectMenuBuilder.ts +++ b/packages/helpers/src/builders/components/MessageSelectMenuBuilder.ts @@ -3,91 +3,101 @@ import type { ComponentEmoji } from '@biscuitland/core'; import { MessageComponentTypes } from '@biscuitland/api-types'; export class SelectMenuOptionBuilder { - constructor() { - this.#data = {} as DiscordSelectOption; - } + constructor() { + this.#data = {} as DiscordSelectOption; + } - #data: DiscordSelectOption; + #data: DiscordSelectOption; - setLabel(label: string): SelectMenuOptionBuilder { - this.#data.label = label; - return this; - } + setLabel(label: string): SelectMenuOptionBuilder { + this.#data.label = label; + return this; + } - setValue(value: string): SelectMenuOptionBuilder { - this.#data.value = value; - return this; - } + setValue(value: string): SelectMenuOptionBuilder { + this.#data.value = value; + return this; + } - setDescription(description: string): SelectMenuOptionBuilder { - this.#data.description = description; - return this; - } + setDescription(description: string): SelectMenuOptionBuilder { + this.#data.description = description; + return this; + } - setDefault(Default = true): SelectMenuOptionBuilder { - this.#data.default = Default; - return this; - } + setDefault(Default = true): SelectMenuOptionBuilder { + this.#data.default = Default; + return this; + } - setEmoji(emoji: ComponentEmoji): SelectMenuOptionBuilder { - this.#data.emoji = emoji; - return this; - } + setEmoji(emoji: ComponentEmoji): SelectMenuOptionBuilder { + this.#data.emoji = emoji; + return this; + } - toJSON(): DiscordSelectOption { - return { ...this.#data }; - } + toJSON(): DiscordSelectOption { + return { ...this.#data }; + } } export class SelectMenuBuilder { - constructor() { - this.#data = {} as DiscordSelectMenuComponent; - this.type = MessageComponentTypes.SelectMenu; - this.options = []; - } + constructor() { + this.#data = {} as DiscordSelectMenuComponent; + this.type = MessageComponentTypes.SelectMenu; + this.options = []; + } - #data: DiscordSelectMenuComponent; - type: MessageComponentTypes.SelectMenu; - options: SelectMenuOptionBuilder[]; + #data: DiscordSelectMenuComponent; + type: MessageComponentTypes.SelectMenu | + MessageComponentTypes.RoleSelect | + MessageComponentTypes.UserSelect | + MessageComponentTypes.MentionableSelect | + MessageComponentTypes.ChannelSelect; - setPlaceholder(placeholder: string): this { - this.#data.placeholder = placeholder; - return this; - } + options: SelectMenuOptionBuilder[]; - setValues(max?: number, min?: number): this { - this.#data.max_values = max; - this.#data.min_values = min; - return this; - } + setType(type: this['type']) { + this.type = type; + return this; + } - setDisabled(disabled = true): this { - this.#data.disabled = disabled; - return this; - } + setPlaceholder(placeholder: string): this { + this.#data.placeholder = placeholder; + return this; + } - setCustomId(id: string): this { - this.#data.custom_id = id; - return this; - } + setValues(max?: number, min?: number): this { + this.#data.max_values = max; + this.#data.min_values = min; + return this; + } - setOptions(...options: SelectMenuOptionBuilder[]): this { - this.options.splice( - 0, - this.options.length, - ...options, - ); - return this; - } + setDisabled(disabled = true): this { + this.#data.disabled = disabled; + return this; + } - addOptions(...options: SelectMenuOptionBuilder[]): this { - this.options.push( - ...options, - ); - return this; - } + setCustomId(id: string): this { + this.#data.custom_id = id; + return this; + } - toJSON(): DiscordSelectMenuComponent { - return { ...this.#data, type: this.type, options: this.options.map(option => option.toJSON()) }; - } + setOptions(...options: SelectMenuOptionBuilder[]): this { + this.options.splice( + 0, + this.options.length, + ...options, + ); + return this; + } + + addOptions(...options: SelectMenuOptionBuilder[]): this { + this.options.push( + ...options, + ); + return this; + } + + toJSON(): DiscordSelectMenuComponent { + return { ...this.#data, type: this.type, options: this.options.map(option => option.toJSON()) }; + } } diff --git a/packages/rest/src/adapters/default-rest-adapter.ts b/packages/rest/src/adapters/default-rest-adapter.ts index e12a247..09f99aa 100644 --- a/packages/rest/src/adapters/default-rest-adapter.ts +++ b/packages/rest/src/adapters/default-rest-adapter.ts @@ -73,7 +73,7 @@ export class DefaultRestAdapter implements RestAdapter { private url: string; constructor(options: DefaultRestOptions) { - this.options = Object.assign(Object.create(DefaultRestAdapter.DEFAULTS), options); + this.options = Object.assign({}, DefaultRestAdapter.DEFAULTS, options); if (this.options.url) { this.url = `${options.url}/v${this.options.version}`; diff --git a/packages/ws/src/services/shard-manager.ts b/packages/ws/src/services/shard-manager.ts index 2b6c9df..c833181 100644 --- a/packages/ws/src/services/shard-manager.ts +++ b/packages/ws/src/services/shard-manager.ts @@ -30,10 +30,10 @@ export class ShardManager { } >(); - readonly shards = new Map(); + readonly shards = new Map(); constructor(options: ShardManagerOptions) { - this.options = Options({}, ShardManager.DEFAULTS, options); + this.options = Options(ShardManager.DEFAULTS, options); } /** Invokes internal processing and respawns shards */ @@ -59,11 +59,11 @@ export class ShardManager { /** Create the start sequence of the shards inside the buckets. */ for (let i = 0; i < gateway.shards; i++) { - const bucketID = i % gateway.session_start_limit.max_concurrency; + const bucketID = i % gateway.session_start_limit.max_concurrency; const bucket = this.buckets.get(bucketID); if (bucket) { - const workerID = Math.floor(i / workers.shards); + const workerID = Math.floor(i / workers.shards); const worker = bucket.workers.find(w => w.id === workerID); if (worker) { @@ -75,22 +75,22 @@ export class ShardManager { } /** Route all shards to workers */ - this.buckets.forEach(async bucket => { - for (const worker of bucket.workers) { + this.buckets.forEach(async bucket => { + for (const worker of bucket.workers) { for (const id of worker.queue) { - await this.connect(id); + await this.connect(id); } - } - }); + } + }); } /** Invokes the bucket to prepare the connection to the shard */ private async connect(id: number): Promise { const { gateway } = this.options; - let shard = this.shards.get(id); + let shard = this.shards.get(id); if (!shard) { shard = new Shard({ @@ -107,8 +107,8 @@ export class ShardManager { }, handleIdentify: async (id: number) => { - await this.buckets.get(id % gateway.session_start_limit.max_concurrency)!.leak.acquire(1); // remove await? - } + await this.buckets.get(id % gateway.session_start_limit.max_concurrency)!.leak.acquire(1); // remove await? + } }); this.shards.set(id, shard); diff --git a/packages/ws/src/services/shard.ts b/packages/ws/src/services/shard.ts index 322bd3a..37407e3 100644 --- a/packages/ws/src/services/shard.ts +++ b/packages/ws/src/services/shard.ts @@ -27,7 +27,7 @@ export class Shard { resumeURL: string | null = null; sessionID: string | null = null; - sequence = 0 ; + sequence = 0; resolves: Map void> = new Map(); @@ -40,7 +40,7 @@ export class Shard { ws: WebSocket | null = null; constructor(options: ShardOptions) { - this.options = Options({}, Shard.DEFAULTS, options); + this.options = Options(Shard.DEFAULTS, options); this.bucket = createLeakyBucket({ max: 120, @@ -78,7 +78,7 @@ export class Shard { this.heartbeatInterval = null; } - connect() { + connect() { if (this.ws && this.ws.readyState !== WebSocket.CLOSED) { return; } @@ -101,7 +101,7 @@ export class Shard { setTimeout(() => resolve(true), this.options.shards.timeout); }); }); - } + } identify() { this.status = 'Identifying'; @@ -110,14 +110,14 @@ export class Shard { op: GatewayOpcodes.Identify, d: { token: `Bot ${this.options.config.token}`, - compress: false, - properties: { - os: 'linux', - device: 'Biscuit', - browser: 'Biscuit' - }, - intents: this.options.config.intents, - shard: [this.options.id, this.options.gateway.shards], + compress: false, + properties: { + os: 'linux', + device: 'Biscuit', + browser: 'Biscuit' + }, + intents: this.options.config.intents, + shard: [this.options.id, this.options.gateway.shards], } }); } @@ -203,7 +203,7 @@ export class Shard { } private async onMessage(data: any, isBinary: boolean) { - const payload = this.pack(data as Buffer | ArrayBuffer, isBinary); + const payload = this.pack(data as Buffer | ArrayBuffer, isBinary); if (payload.s != null) { this.sequence = payload.s;