mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-02 21:16:09 +00:00
new select menus (#122)
This commit is contained in:
parent
6a5fce0f58
commit
f6b745c726
@ -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, K extends keyof T> = T & { [P in K]-?: T[P] };
|
||||
// THANK YOU YUI FOR SHARING THIS!
|
||||
export type CamelCase<S extends string> =
|
||||
S extends `${infer P1}_${infer P2}${infer P3}`
|
||||
? `${Lowercase<P1>}${Uppercase<P2>}${CamelCase<P3>}`
|
||||
: Lowercase<S>;
|
||||
? `${Lowercase<P1>}${Uppercase<P2>}${CamelCase<P3>}`
|
||||
: Lowercase<S>;
|
||||
export type Camelize<T> = {
|
||||
// eslint-disable-next-line @typescript-eslint/array-type
|
||||
[K in keyof T as CamelCase<string & K>]: T[K] extends Array<infer U>
|
||||
? // eslint-disable-next-line @typescript-eslint/ban-types
|
||||
U extends {}
|
||||
? // eslint-disable-next-line @typescript-eslint/array-type
|
||||
Array<Camelize<U>>
|
||||
: T[K]
|
||||
: // eslint-disable-next-line @typescript-eslint/ban-types
|
||||
T[K] extends {}
|
||||
? Camelize<T[K]>
|
||||
: never;
|
||||
? // eslint-disable-next-line @typescript-eslint/ban-types
|
||||
U extends {}
|
||||
? // eslint-disable-next-line @typescript-eslint/array-type
|
||||
Array<Camelize<U>>
|
||||
: T[K]
|
||||
: // eslint-disable-next-line @typescript-eslint/ban-types
|
||||
T[K] extends {}
|
||||
? Camelize<T[K]>
|
||||
: never;
|
||||
};
|
||||
|
||||
export type PickPartial<T, K extends keyof T> = {
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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()) };
|
||||
}
|
||||
}
|
||||
|
@ -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}`;
|
||||
|
@ -30,10 +30,10 @@ export class ShardManager {
|
||||
}
|
||||
>();
|
||||
|
||||
readonly shards = new Map<number, Shard>();
|
||||
readonly shards = new Map<number, Shard>();
|
||||
|
||||
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<Shard> {
|
||||
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);
|
||||
|
@ -27,7 +27,7 @@ export class Shard {
|
||||
resumeURL: string | null = null;
|
||||
sessionID: string | null = null;
|
||||
|
||||
sequence = 0 ;
|
||||
sequence = 0;
|
||||
|
||||
resolves: Map<string, (payload?: unknown) => 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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user