mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-02 04:56:07 +00:00
chore: 3.1.0 (#339)
* perf: optimize members cache * feat: components V2 (#337) * feat: components v2 * fix: build * chore: apply formatting * refactor(components): some types * refactor(types): replace TopLevelComponents with APITopLevelComponent in REST * fix: unify components * refactor(TextDisplay): rename content method to setContent for clarity * refactor(builders): add missing builder from component * fix: touche * feat(webhook): webhook params for components v2 --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix: use protected instead of private * fix(editOrReply): accept flags when editing message * feat: add onBeforeMiddlewares and onBeforeOptions (#338) * chore: package version --------- Co-authored-by: MARCROCK22 <marcos22dev@gmail.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: MARCROCK22 <57925328+MARCROCK22@users.noreply.github.com>
This commit is contained in:
parent
ce3d75121d
commit
e3b6f57741
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "seyfert",
|
"name": "seyfert",
|
||||||
"version": "3.0.0",
|
"version": "3.1.0",
|
||||||
"description": "The most advanced framework for discord bots",
|
"description": "The most advanced framework for discord bots",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"module": "./lib/index.js",
|
"module": "./lib/index.js",
|
||||||
|
@ -9,6 +9,7 @@ import type {
|
|||||||
RESTPatchAPIWebhookResult,
|
RESTPatchAPIWebhookResult,
|
||||||
RESTPatchAPIWebhookWithTokenJSONBody,
|
RESTPatchAPIWebhookWithTokenJSONBody,
|
||||||
RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
||||||
|
RESTPatchAPIWebhookWithTokenMessageQuery,
|
||||||
RESTPatchAPIWebhookWithTokenMessageResult,
|
RESTPatchAPIWebhookWithTokenMessageResult,
|
||||||
RESTPatchAPIWebhookWithTokenResult,
|
RESTPatchAPIWebhookWithTokenResult,
|
||||||
RESTPostAPIWebhookWithTokenGitHubQuery,
|
RESTPostAPIWebhookWithTokenGitHubQuery,
|
||||||
@ -33,7 +34,9 @@ export interface WebhookRoutes {
|
|||||||
token: string,
|
token: string,
|
||||||
): {
|
): {
|
||||||
get(args?: RestArgumentsNoBody): Promise<RESTGetAPIWebhookWithTokenResult>;
|
get(args?: RestArgumentsNoBody): Promise<RESTGetAPIWebhookWithTokenResult>;
|
||||||
patch(args: RestArguments<RESTPatchAPIWebhookWithTokenJSONBody>): Promise<RESTPatchAPIWebhookWithTokenResult>;
|
patch(
|
||||||
|
args: RestArguments<RESTPatchAPIWebhookWithTokenJSONBody, RESTPatchAPIWebhookWithTokenMessageQuery>,
|
||||||
|
): Promise<RESTPatchAPIWebhookWithTokenResult>;
|
||||||
delete(args?: RestArgumentsNoBody): Promise<RESTDeleteAPIWebhookWithTokenResult>;
|
delete(args?: RestArgumentsNoBody): Promise<RESTDeleteAPIWebhookWithTokenResult>;
|
||||||
post(
|
post(
|
||||||
args: RestArguments<RESTPostAPIWebhookWithTokenJSONBody, RESTPostAPIWebhookWithTokenQuery>,
|
args: RestArguments<RESTPostAPIWebhookWithTokenJSONBody, RESTPostAPIWebhookWithTokenQuery>,
|
||||||
|
@ -98,13 +98,13 @@ export class ApiHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#randomUUID(): UUID {
|
randomUUID(): UUID {
|
||||||
const uuid = randomUUID();
|
const uuid = randomUUID();
|
||||||
if (this.workerPromises!.has(uuid)) return this.#randomUUID();
|
if (this.workerPromises!.has(uuid)) return this.randomUUID();
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private sendMessage(_body: WorkerSendApiRequest) {
|
protected sendMessage(_body: WorkerSendApiRequest) {
|
||||||
throw new Error('Function not implemented');
|
throw new Error('Function not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ export class ApiHandler {
|
|||||||
{ auth = true, ...request }: ApiRequestOptions = {},
|
{ auth = true, ...request }: ApiRequestOptions = {},
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
if (this.options.workerProxy) {
|
if (this.options.workerProxy) {
|
||||||
const nonce = this.#randomUUID();
|
const nonce = this.randomUUID();
|
||||||
return this.postMessage<T>({
|
return this.postMessage<T>({
|
||||||
method,
|
method,
|
||||||
url,
|
url,
|
||||||
|
@ -7,13 +7,13 @@ import {
|
|||||||
} from '../types';
|
} from '../types';
|
||||||
import { BaseComponentBuilder } from './Base';
|
import { BaseComponentBuilder } from './Base';
|
||||||
import { fromComponent } from './index';
|
import { fromComponent } from './index';
|
||||||
import type { BuilderComponents, FixedComponents } from './types';
|
import type { ActionBuilderComponents, FixedComponents } from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an Action Row component in a message.
|
* Represents an Action Row component in a message.
|
||||||
* @template T - The type of components in the Action Row.
|
* @template T - The type of components in the Action Row.
|
||||||
*/
|
*/
|
||||||
export class ActionRow<T extends BuilderComponents> extends BaseComponentBuilder<
|
export class ActionRow<T extends ActionBuilderComponents = ActionBuilderComponents> extends BaseComponentBuilder<
|
||||||
APIActionRowComponent<APIActionRowComponentTypes>
|
APIActionRowComponent<APIActionRowComponentTypes>
|
||||||
> {
|
> {
|
||||||
/**
|
/**
|
||||||
@ -50,8 +50,8 @@ export class ActionRow<T extends BuilderComponents> extends BaseComponentBuilder
|
|||||||
* @example
|
* @example
|
||||||
* actionRow.setComponents([buttonComponent1, buttonComponent2]);
|
* actionRow.setComponents([buttonComponent1, buttonComponent2]);
|
||||||
*/
|
*/
|
||||||
setComponents(component: FixedComponents<T>[]): this {
|
setComponents(...component: RestOrArray<FixedComponents<T>>): this {
|
||||||
this.components = [...component];
|
this.components = component.flat() as FixedComponents<T>[];
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
import { type EmojiResolvable, resolvePartialEmoji } from '../common';
|
import { type EmojiResolvable, resolvePartialEmoji } from '../common';
|
||||||
import { type APIButtonComponent, type APIMessageComponentEmoji, type ButtonStyle, ComponentType } from '../types';
|
import { type APIButtonComponent, type APIMessageComponentEmoji, type ButtonStyle, ComponentType } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a button component.
|
* Represents a button component.
|
||||||
* @template Type - The type of the button component.
|
* @template Type - The type of the button component.
|
||||||
*/
|
*/
|
||||||
export class Button {
|
export class Button extends BaseComponentBuilder<APIButtonComponent> {
|
||||||
/**
|
constructor(data: Partial<APIButtonComponent> = {}) {
|
||||||
* Creates a new Button instance.
|
super({ type: ComponentType.Button, ...data });
|
||||||
* @param data - The initial data for the button.
|
|
||||||
*/
|
|
||||||
constructor(public data: Partial<APIButtonComponent> = {}) {
|
|
||||||
this.data.type = ComponentType.Button;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,12 +73,4 @@ export class Button {
|
|||||||
(this.data as Extract<APIButtonComponent, { sku_id?: string }>).sku_id = skuId;
|
(this.data as Extract<APIButtonComponent, { sku_id?: string }>).sku_id = skuId;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the Button instance to its JSON representation.
|
|
||||||
* @returns The JSON representation of the Button instance.
|
|
||||||
*/
|
|
||||||
toJSON() {
|
|
||||||
return { ...this.data } as Partial<APIButtonComponent>;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
100
src/builders/Container.ts
Normal file
100
src/builders/Container.ts
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import { type ActionRow, fromComponent } from '.';
|
||||||
|
import { type ColorResolvable, type RestOrArray, resolveColor } from '../common';
|
||||||
|
import { type APIContainerComponent, ComponentType } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
import type { File } from './File';
|
||||||
|
import type { MediaGallery } from './MediaGallery';
|
||||||
|
import type { Section } from './Section';
|
||||||
|
import type { Separator } from './Separator';
|
||||||
|
import type { TextDisplay } from './TextDisplay';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the possible component types that can be added to a Container.
|
||||||
|
*/
|
||||||
|
export type ContainerBuilderComponents = ActionRow | TextDisplay | Section | MediaGallery | Separator | File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a container component builder.
|
||||||
|
* Containers group other components together.
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const container = new Container()
|
||||||
|
* .addComponents(
|
||||||
|
* new TextDisplay('This is text inside a container!'),
|
||||||
|
* new ActionRow().addComponents(new Button().setLabel('Click me!'))
|
||||||
|
* )
|
||||||
|
* .setColor('Blue');
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class Container extends BaseComponentBuilder<APIContainerComponent> {
|
||||||
|
/**
|
||||||
|
* The components held within this container.
|
||||||
|
*/
|
||||||
|
components: ContainerBuilderComponents[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new Container.
|
||||||
|
* @param data Optional initial data for the container.
|
||||||
|
*/
|
||||||
|
constructor({ components, ...data }: Partial<APIContainerComponent> = {}) {
|
||||||
|
super({ ...data, type: ComponentType.Container });
|
||||||
|
this.components = (components?.map(fromComponent) ?? []) as ContainerBuilderComponents[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds components to the container.
|
||||||
|
* @param components The components to add. Can be a single component, an array of components, or multiple components as arguments.
|
||||||
|
* @returns The updated Container instance.
|
||||||
|
*/
|
||||||
|
addComponents(...components: RestOrArray<ContainerBuilderComponents>) {
|
||||||
|
this.components = this.components.concat(components.flat());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the components for the container, replacing any existing components.
|
||||||
|
* @param components The components to set. Can be a single component, an array of components, or multiple components as arguments.
|
||||||
|
* @returns The updated Container instance.
|
||||||
|
*/
|
||||||
|
setComponents(...components: RestOrArray<ContainerBuilderComponents>) {
|
||||||
|
this.components = components.flat();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the container's content should be visually marked as a spoiler.
|
||||||
|
* @param spoiler Whether the content is a spoiler (defaults to true).
|
||||||
|
* @returns The updated Container instance.
|
||||||
|
*/
|
||||||
|
setSpoiler(spoiler = true) {
|
||||||
|
this.data.spoiler = spoiler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the accent color for the container.
|
||||||
|
* @param color The color resolvable (e.g., hex code, color name, integer).
|
||||||
|
* @returns The updated Container instance.
|
||||||
|
*/
|
||||||
|
setColor(color: ColorResolvable) {
|
||||||
|
this.data.accent_color = resolveColor(color);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ID for the container.
|
||||||
|
* @param id The ID to set.
|
||||||
|
* @returns The updated Container instance.
|
||||||
|
*/
|
||||||
|
setId(id: number) {
|
||||||
|
this.data.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
...this.data,
|
||||||
|
components: this.components.map(c => c.toJSON()),
|
||||||
|
} as APIContainerComponent;
|
||||||
|
}
|
||||||
|
}
|
52
src/builders/File.ts
Normal file
52
src/builders/File.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { type APIFileComponent, ComponentType } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a file component builder.
|
||||||
|
* Used to display files within containers.
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const file = new File()
|
||||||
|
* .setMedia('https://example.com/image.png')
|
||||||
|
* .setSpoiler();
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class File extends BaseComponentBuilder<APIFileComponent> {
|
||||||
|
/**
|
||||||
|
* Constructs a new File component.
|
||||||
|
* @param data Optional initial data for the file component.
|
||||||
|
*/
|
||||||
|
constructor(data: Partial<APIFileComponent> = {}) {
|
||||||
|
super({ type: ComponentType.File, ...data });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ID for the file component.
|
||||||
|
* @param id The ID to set.
|
||||||
|
* @returns The updated File instance.
|
||||||
|
*/
|
||||||
|
setId(id: number) {
|
||||||
|
this.data.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the media URL for the file.
|
||||||
|
* @param url The URL of the file to display.
|
||||||
|
* @returns The updated File instance.
|
||||||
|
*/
|
||||||
|
setMedia(url: string) {
|
||||||
|
this.data.file = { url };
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the file should be visually marked as a spoiler.
|
||||||
|
* @param spoiler Whether the file is a spoiler (defaults to true).
|
||||||
|
* @returns The updated File instance.
|
||||||
|
*/
|
||||||
|
setSpoiler(spoiler = true) {
|
||||||
|
this.data.spoiler = spoiler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
112
src/builders/MediaGallery.ts
Normal file
112
src/builders/MediaGallery.ts
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import type { RestOrArray } from '../common';
|
||||||
|
import { type APIMediaGalleryComponent, type APIMediaGalleryItems, ComponentType } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a media gallery component builder.
|
||||||
|
* Used to display a collection of media items.
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const gallery = new MediaGallery()
|
||||||
|
* .addItems(
|
||||||
|
* new MediaGalleryItem().setMedia('https://example.com/image1.png').setDescription('Image 1'),
|
||||||
|
* new MediaGalleryItem().setMedia('https://example.com/image2.jpg').setSpoiler()
|
||||||
|
* );
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class MediaGallery extends BaseComponentBuilder<APIMediaGalleryComponent> {
|
||||||
|
items: MediaGalleryItem[];
|
||||||
|
/**
|
||||||
|
* Constructs a new MediaGallery.
|
||||||
|
* @param data Optional initial data for the media gallery.
|
||||||
|
*/
|
||||||
|
constructor({ items, ...data }: Partial<APIMediaGalleryComponent> = {}) {
|
||||||
|
super({ type: ComponentType.MediaGallery, ...data });
|
||||||
|
this.items = (items?.map(i => new MediaGalleryItem(i)) ?? []) as MediaGalleryItem[];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Sets the ID for the media gallery component.
|
||||||
|
* @param id The ID to set.
|
||||||
|
* @returns The updated MediaGallery instance.
|
||||||
|
*/
|
||||||
|
setId(id: number) {
|
||||||
|
this.data.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds items to the media gallery.
|
||||||
|
* @param items The items to add. Can be a single item, an array of items, or multiple items as arguments.
|
||||||
|
* @returns The updated MediaGallery instance.
|
||||||
|
*/
|
||||||
|
addItems(...items: RestOrArray<MediaGalleryItem>) {
|
||||||
|
this.items = this.items.concat(items.flat());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the items for the media gallery, replacing any existing items.
|
||||||
|
* @param items The items to set. Can be a single item, an array of items, or multiple items as arguments.
|
||||||
|
* @returns The updated MediaGallery instance.
|
||||||
|
*/
|
||||||
|
setItems(...items: RestOrArray<MediaGalleryItem>) {
|
||||||
|
this.items = items.flat();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
...this.data,
|
||||||
|
items: this.items.map(i => i.toJSON()),
|
||||||
|
} as APIMediaGalleryComponent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an item within a MediaGallery.
|
||||||
|
*/
|
||||||
|
export class MediaGalleryItem {
|
||||||
|
/**
|
||||||
|
* Constructs a new MediaGalleryItem.
|
||||||
|
* @param data Optional initial data for the media gallery item.
|
||||||
|
*/
|
||||||
|
constructor(public data: Partial<APIMediaGalleryItems> = {}) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the media URL for this gallery item.
|
||||||
|
* @param url The URL of the media.
|
||||||
|
* @returns The updated MediaGalleryItem instance.
|
||||||
|
*/
|
||||||
|
setMedia(url: string) {
|
||||||
|
this.data.media = { url };
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the description for this gallery item.
|
||||||
|
* @param desc The description text.
|
||||||
|
* @returns The updated MediaGalleryItem instance.
|
||||||
|
*/
|
||||||
|
setDescription(desc: string) {
|
||||||
|
this.data.description = desc;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this gallery item should be visually marked as a spoiler.
|
||||||
|
* @param spoiler Whether the item is a spoiler (defaults to true).
|
||||||
|
* @returns The updated MediaGalleryItem instance.
|
||||||
|
*/
|
||||||
|
setSpoiler(spoiler = true) {
|
||||||
|
this.data.spoiler = spoiler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts this MediaGalleryItem instance to its JSON representation.
|
||||||
|
* @returns The JSON representation of the item data.
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return { ...this.data };
|
||||||
|
}
|
||||||
|
}
|
55
src/builders/Section.ts
Normal file
55
src/builders/Section.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { type Button, fromComponent } from '.';
|
||||||
|
import type { RestOrArray } from '../common';
|
||||||
|
import { type APISectionComponent, ComponentType } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
import type { TextDisplay } from './TextDisplay';
|
||||||
|
import type { Thumbnail } from './Thumbnail';
|
||||||
|
|
||||||
|
export class Section<
|
||||||
|
Ac extends Button | Thumbnail = Button | Thumbnail,
|
||||||
|
> extends BaseComponentBuilder<APISectionComponent> {
|
||||||
|
components: TextDisplay[];
|
||||||
|
accessory!: Ac;
|
||||||
|
constructor({ components, accessory, ...data }: Partial<APISectionComponent> = {}) {
|
||||||
|
super({ type: ComponentType.Section, ...data });
|
||||||
|
this.components = (components?.map(component => fromComponent(component)) ?? []) as TextDisplay[];
|
||||||
|
if (accessory) this.accessory = fromComponent(accessory) as Ac;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds components to this section.
|
||||||
|
* @param components The components to add
|
||||||
|
* @example section.addComponents(new TextDisplay().content('Hello'));
|
||||||
|
*/
|
||||||
|
addComponents(...components: RestOrArray<TextDisplay>) {
|
||||||
|
this.components = this.components.concat(components.flat());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the components for this section.
|
||||||
|
* @param components The components to set
|
||||||
|
* @example section.setComponents(new TextDisplay().content('Hello'));
|
||||||
|
*/
|
||||||
|
setComponents(...components: RestOrArray<TextDisplay>) {
|
||||||
|
this.components = components.flat();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAccessory(accessory: Ac) {
|
||||||
|
this.accessory = accessory;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts this section to JSON.
|
||||||
|
* @returns The JSON representation of this section
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
...this.data,
|
||||||
|
components: this.components.map(component => component.toJSON()),
|
||||||
|
accessory: this.accessory.toJSON(),
|
||||||
|
} as APISectionComponent;
|
||||||
|
}
|
||||||
|
}
|
54
src/builders/Separator.ts
Normal file
54
src/builders/Separator.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { type APISeparatorComponent, ComponentType, type Spacing } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a separator component builder.
|
||||||
|
* Used to add visual spacing or dividers between components.
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* // A simple separator for spacing
|
||||||
|
* const spacingSeparator = new Separator().setSpacing(Spacing.Small);
|
||||||
|
*
|
||||||
|
* // A separator acting as a visual divider
|
||||||
|
* const dividerSeparator = new Separator().setDivider(true);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class Separator extends BaseComponentBuilder<APISeparatorComponent> {
|
||||||
|
/**
|
||||||
|
* Constructs a new Separator component.
|
||||||
|
* @param data Optional initial data for the separator component.
|
||||||
|
*/
|
||||||
|
constructor(data: Partial<APISeparatorComponent> = {}) {
|
||||||
|
super({ type: ComponentType.Separator, ...data });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ID for the separator component.
|
||||||
|
* @param id The ID to set.
|
||||||
|
* @returns The updated Separator instance.
|
||||||
|
*/
|
||||||
|
setId(id: number) {
|
||||||
|
this.data.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this separator should act as a visual divider.
|
||||||
|
* @param divider Whether to render as a divider (defaults to false).
|
||||||
|
* @returns The updated Separator instance.
|
||||||
|
*/
|
||||||
|
setDivider(divider = false) {
|
||||||
|
this.data.divider = divider;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the amount of spacing this separator provides.
|
||||||
|
* @param spacing The desired spacing level ('None', 'Small', 'Medium', 'Large').
|
||||||
|
* @returns The updated Separator instance.
|
||||||
|
*/
|
||||||
|
setSpacing(spacing: Spacing) {
|
||||||
|
this.data.spacing = spacing;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
40
src/builders/TextDisplay.ts
Normal file
40
src/builders/TextDisplay.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { type APITextDispalyComponent, ComponentType } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a text display component builder.
|
||||||
|
* Used to display simple text content.
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const text = new TextDisplay().content('Hello, world!');
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class TextDisplay extends BaseComponentBuilder<APITextDispalyComponent> {
|
||||||
|
/**
|
||||||
|
* Constructs a new TextDisplay component.
|
||||||
|
* @param data Optional initial data for the text display component.
|
||||||
|
*/
|
||||||
|
constructor(data: Partial<APITextDispalyComponent> = {}) {
|
||||||
|
super({ type: ComponentType.TextDisplay, ...data });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ID for the text display component.
|
||||||
|
* @param id The ID to set.
|
||||||
|
* @returns The updated TextDisplay instance.
|
||||||
|
*/
|
||||||
|
setId(id: number) {
|
||||||
|
this.data.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the text content to display.
|
||||||
|
* @param content The text content.
|
||||||
|
* @returns The updated TextDisplay instance.
|
||||||
|
*/
|
||||||
|
setContent(content: string) {
|
||||||
|
this.data.content = content;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
62
src/builders/Thumbnail.ts
Normal file
62
src/builders/Thumbnail.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { type APIThumbnailComponent, ComponentType } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a thumbnail component builder.
|
||||||
|
* Used to display a small image preview, often alongside other content.
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const thumbnail = new Thumbnail()
|
||||||
|
* .setMedia('https://example.com/thumbnail.jpg')
|
||||||
|
* .setDescription('A cool thumbnail');
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class Thumbnail extends BaseComponentBuilder<APIThumbnailComponent> {
|
||||||
|
/**
|
||||||
|
* Constructs a new Thumbnail component.
|
||||||
|
* @param data Optional initial data for the thumbnail component.
|
||||||
|
*/
|
||||||
|
constructor(data: Partial<APIThumbnailComponent> = {}) {
|
||||||
|
super({ type: ComponentType.Thumbnail, ...data });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the thumbnail should be visually marked as a spoiler.
|
||||||
|
* @param spoiler Whether the thumbnail is a spoiler (defaults to true).
|
||||||
|
* @returns The updated Thumbnail instance.
|
||||||
|
*/
|
||||||
|
setSpoiler(spoiler = true) {
|
||||||
|
this.data.spoiler = spoiler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the description for the thumbnail.
|
||||||
|
* @param description The description text. Can be undefined to remove the description.
|
||||||
|
* @returns The updated Thumbnail instance.
|
||||||
|
*/
|
||||||
|
setDescription(description: string | undefined) {
|
||||||
|
this.data.description = description;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ID for the thumbnail component.
|
||||||
|
* @param id The ID to set.
|
||||||
|
* @returns The updated Thumbnail instance.
|
||||||
|
*/
|
||||||
|
setId(id: number) {
|
||||||
|
this.data.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the media URL for the thumbnail.
|
||||||
|
* @param url The URL of the image to display as a thumbnail.
|
||||||
|
* @returns The updated Thumbnail instance.
|
||||||
|
*/
|
||||||
|
setMedia(url: string) {
|
||||||
|
this.data.media = { url };
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,11 @@
|
|||||||
import { type APIActionRowComponent, type APIActionRowComponentTypes, ComponentType } from '../types';
|
import { type APIComponents, ComponentType } from '../types';
|
||||||
import { ActionRow } from './ActionRow';
|
import { ActionRow } from './ActionRow';
|
||||||
import { Button } from './Button';
|
import { Button } from './Button';
|
||||||
|
import { Container } from './Container';
|
||||||
|
import { File } from './File';
|
||||||
|
import { MediaGallery } from './MediaGallery';
|
||||||
import { TextInput } from './Modal';
|
import { TextInput } from './Modal';
|
||||||
|
import { Section } from './Section';
|
||||||
import {
|
import {
|
||||||
ChannelSelectMenu,
|
ChannelSelectMenu,
|
||||||
MentionableSelectMenu,
|
MentionableSelectMenu,
|
||||||
@ -9,29 +13,32 @@ import {
|
|||||||
StringSelectMenu,
|
StringSelectMenu,
|
||||||
UserSelectMenu,
|
UserSelectMenu,
|
||||||
} from './SelectMenu';
|
} from './SelectMenu';
|
||||||
|
import { Separator } from './Separator';
|
||||||
|
import { TextDisplay } from './TextDisplay';
|
||||||
|
import { Thumbnail } from './Thumbnail';
|
||||||
import type { BuilderComponents } from './types';
|
import type { BuilderComponents } from './types';
|
||||||
|
|
||||||
export * from './ActionRow';
|
export * from './ActionRow';
|
||||||
export * from './Attachment';
|
export * from './Attachment';
|
||||||
export * from './Base';
|
export * from './Base';
|
||||||
export * from './Button';
|
export * from './Button';
|
||||||
|
export * from './Container';
|
||||||
export * from './Embed';
|
export * from './Embed';
|
||||||
|
export * from './File';
|
||||||
|
export * from './MediaGallery';
|
||||||
export * from './Modal';
|
export * from './Modal';
|
||||||
export * from './SelectMenu';
|
|
||||||
export * from './Poll';
|
export * from './Poll';
|
||||||
|
export * from './Section';
|
||||||
|
export * from './SelectMenu';
|
||||||
|
export * from './Separator';
|
||||||
|
export * from './TextDisplay';
|
||||||
|
export * from './Thumbnail';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|
||||||
export function fromComponent(
|
export function fromComponent(data: BuilderComponents | APIComponents): BuilderComponents {
|
||||||
data:
|
|
||||||
| BuilderComponents
|
|
||||||
| APIActionRowComponentTypes
|
|
||||||
| APIActionRowComponent<APIActionRowComponentTypes>
|
|
||||||
| ActionRow<BuilderComponents>,
|
|
||||||
): BuilderComponents | ActionRow<BuilderComponents> {
|
|
||||||
if ('toJSON' in data) {
|
if ('toJSON' in data) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case ComponentType.Button:
|
case ComponentType.Button:
|
||||||
return new Button(data);
|
return new Button(data);
|
||||||
@ -49,5 +56,19 @@ export function fromComponent(
|
|||||||
return new ChannelSelectMenu(data);
|
return new ChannelSelectMenu(data);
|
||||||
case ComponentType.ActionRow:
|
case ComponentType.ActionRow:
|
||||||
return new ActionRow(data);
|
return new ActionRow(data);
|
||||||
|
case ComponentType.Section:
|
||||||
|
return new Section(data);
|
||||||
|
case ComponentType.TextDisplay:
|
||||||
|
return new TextDisplay(data);
|
||||||
|
case ComponentType.Thumbnail:
|
||||||
|
return new Thumbnail(data);
|
||||||
|
case ComponentType.Container:
|
||||||
|
return new Container(data);
|
||||||
|
case ComponentType.MediaGallery:
|
||||||
|
return new MediaGallery(data);
|
||||||
|
case ComponentType.Separator:
|
||||||
|
return new Separator(data);
|
||||||
|
case ComponentType.File:
|
||||||
|
return new File(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,17 @@ import type {
|
|||||||
ModalSubmitInteraction,
|
ModalSubmitInteraction,
|
||||||
StringSelectMenuInteraction,
|
StringSelectMenuInteraction,
|
||||||
} from '../structures/Interaction';
|
} from '../structures/Interaction';
|
||||||
|
import type { ActionRow } from './ActionRow';
|
||||||
import type { Button } from './Button';
|
import type { Button } from './Button';
|
||||||
|
import type { Container } from './Container';
|
||||||
|
import type { File } from './File';
|
||||||
|
import type { MediaGallery } from './MediaGallery';
|
||||||
import type { TextInput } from './Modal';
|
import type { TextInput } from './Modal';
|
||||||
|
import type { Section } from './Section';
|
||||||
import type { BuilderSelectMenus } from './SelectMenu';
|
import type { BuilderSelectMenus } from './SelectMenu';
|
||||||
|
import type { Separator } from './Separator';
|
||||||
|
import type { TextDisplay } from './TextDisplay';
|
||||||
|
import type { Thumbnail } from './Thumbnail';
|
||||||
|
|
||||||
export type ComponentCallback<
|
export type ComponentCallback<
|
||||||
T extends ComponentInteraction | StringSelectMenuInteraction = ComponentInteraction | StringSelectMenuInteraction,
|
T extends ComponentInteraction | StringSelectMenuInteraction = ComponentInteraction | StringSelectMenuInteraction,
|
||||||
@ -25,7 +33,22 @@ export type ButtonID = Omit<Button, 'setURL'>;
|
|||||||
|
|
||||||
export type MessageBuilderComponents = FixedComponents<Button> | BuilderSelectMenus;
|
export type MessageBuilderComponents = FixedComponents<Button> | BuilderSelectMenus;
|
||||||
export type ModalBuilderComponents = TextInput;
|
export type ModalBuilderComponents = TextInput;
|
||||||
export type BuilderComponents = MessageBuilderComponents | TextInput;
|
export type ActionBuilderComponents = MessageBuilderComponents | TextInput;
|
||||||
|
|
||||||
|
export type BuilderComponents =
|
||||||
|
| ActionRow
|
||||||
|
| ActionBuilderComponents
|
||||||
|
| Section<Button | Thumbnail>
|
||||||
|
| Thumbnail
|
||||||
|
| TextDisplay
|
||||||
|
| Container
|
||||||
|
| Separator
|
||||||
|
| MediaGallery
|
||||||
|
| File
|
||||||
|
| TextInput;
|
||||||
|
|
||||||
|
export type TopLevelBuilders = Exclude<BuilderComponents, Thumbnail | TextInput>;
|
||||||
|
|
||||||
export type FixedComponents<T = Button> = T extends Button ? ButtonLink | ButtonID : T;
|
export type FixedComponents<T = Button> = T extends Button ? ButtonLink | ButtonID : T;
|
||||||
export interface ListenerOptions {
|
export interface ListenerOptions {
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
|
6
src/cache/resources/guilds.ts
vendored
6
src/cache/resources/guilds.ts
vendored
@ -18,7 +18,7 @@ export class Guilds extends BaseResource<any, APIGuild | GatewayGuildCreateDispa
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
raw(id: string): ReturnCache<APIGuild | undefined> {
|
raw(id: string): ReturnCache<(APIGuild & { member_count?: number }) | undefined> {
|
||||||
return super.get(id);
|
return super.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ export class Guilds extends BaseResource<any, APIGuild | GatewayGuildCreateDispa
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bulkRaw(ids: string[]): ReturnCache<APIGuild[]> {
|
bulkRaw(ids: string[]): ReturnCache<(APIGuild & { member_count?: number })[]> {
|
||||||
return super.bulk(ids);
|
return super.bulk(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ export class Guilds extends BaseResource<any, APIGuild | GatewayGuildCreateDispa
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
valuesRaw(): ReturnCache<APIGuild[]> {
|
valuesRaw(): ReturnCache<(APIGuild & { member_count?: number })[]> {
|
||||||
return super.values();
|
return super.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
36
src/cache/resources/members.ts
vendored
36
src/cache/resources/members.ts
vendored
@ -1,7 +1,7 @@
|
|||||||
import type { CacheFrom, ReturnCache } from '../..';
|
import type { CacheFrom, ReturnCache } from '../..';
|
||||||
import { type GuildMemberStructure, Transformers } from '../../client/transformers';
|
import { type GuildMemberStructure, Transformers } from '../../client/transformers';
|
||||||
import { fakePromise } from '../../common';
|
import { fakePromise } from '../../common';
|
||||||
import type { APIGuildMember } from '../../types';
|
import type { APIGuildMember, APIUser } from '../../types';
|
||||||
import { GuildBasedResource } from './default/guild-based';
|
import { GuildBasedResource } from './default/guild-based';
|
||||||
export class Members extends GuildBasedResource<any, APIGuildMember> {
|
export class Members extends GuildBasedResource<any, APIGuildMember> {
|
||||||
namespace = 'member';
|
namespace = 'member';
|
||||||
@ -39,14 +39,21 @@ export class Members extends GuildBasedResource<any, APIGuildMember> {
|
|||||||
|
|
||||||
override bulk(ids: string[], guild: string): ReturnCache<GuildMemberStructure[]> {
|
override bulk(ids: string[], guild: string): ReturnCache<GuildMemberStructure[]> {
|
||||||
return fakePromise(super.bulk(ids, guild)).then(members =>
|
return fakePromise(super.bulk(ids, guild)).then(members =>
|
||||||
fakePromise(this.client.cache.users?.bulkRaw(ids)).then(users =>
|
fakePromise(this.client.cache.users?.bulkRaw(ids)).then(users => {
|
||||||
members
|
if (!users) return [];
|
||||||
|
let usersRecord: null | Partial<Record<string, APIUser>> = {};
|
||||||
|
for (const user of users) {
|
||||||
|
usersRecord[user.id] = user;
|
||||||
|
}
|
||||||
|
const result = members
|
||||||
.map(rawMember => {
|
.map(rawMember => {
|
||||||
const user = users?.find(x => x.id === rawMember.id);
|
const user = usersRecord![rawMember.id];
|
||||||
return user ? Transformers.GuildMember(this.client, rawMember, user, guild) : undefined;
|
return user ? Transformers.GuildMember(this.client, rawMember, user, guild) : undefined;
|
||||||
})
|
})
|
||||||
.filter(x => x !== undefined),
|
.filter(x => x !== undefined);
|
||||||
),
|
usersRecord = null;
|
||||||
|
return result;
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,14 +63,21 @@ export class Members extends GuildBasedResource<any, APIGuildMember> {
|
|||||||
|
|
||||||
override values(guild: string): ReturnCache<GuildMemberStructure[]> {
|
override values(guild: string): ReturnCache<GuildMemberStructure[]> {
|
||||||
return fakePromise(super.values(guild)).then(members =>
|
return fakePromise(super.values(guild)).then(members =>
|
||||||
fakePromise(this.client.cache.users?.valuesRaw()).then(users =>
|
fakePromise(this.client.cache.users?.bulkRaw(members.map(member => member.id))).then(users => {
|
||||||
members
|
if (!users) return [];
|
||||||
|
let usersRecord: null | Partial<Record<string, APIUser>> = {};
|
||||||
|
for (const user of users) {
|
||||||
|
usersRecord[user.id] = user;
|
||||||
|
}
|
||||||
|
const result = members
|
||||||
.map(rawMember => {
|
.map(rawMember => {
|
||||||
const user = users?.find(x => x.id === rawMember.id);
|
const user = usersRecord![rawMember.id];
|
||||||
return user ? Transformers.GuildMember(this.client, rawMember, user, rawMember.guild_id) : undefined;
|
return user ? Transformers.GuildMember(this.client, rawMember, user, rawMember.guild_id) : undefined;
|
||||||
})
|
})
|
||||||
.filter(x => x !== undefined),
|
.filter(x => x !== undefined);
|
||||||
),
|
usersRecord = null;
|
||||||
|
return result;
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,6 +470,8 @@ export interface BaseClientOptions {
|
|||||||
globalMiddlewares?: readonly (keyof RegisteredMiddlewares)[];
|
globalMiddlewares?: readonly (keyof RegisteredMiddlewares)[];
|
||||||
commands?: {
|
commands?: {
|
||||||
defaults?: {
|
defaults?: {
|
||||||
|
onBeforeMiddlewares?: (context: CommandContext | MenuCommandContext<any, never>) => unknown;
|
||||||
|
onBeforeOptions?: Command['onBeforeOptions'];
|
||||||
onRunError?: (context: MenuCommandContext<any, never> | CommandContext, error: unknown) => unknown;
|
onRunError?: (context: MenuCommandContext<any, never> | CommandContext, error: unknown) => unknown;
|
||||||
onPermissionsFail?: Command['onPermissionsFail'];
|
onPermissionsFail?: Command['onPermissionsFail'];
|
||||||
onBotPermissionsFail?: (
|
onBotPermissionsFail?: (
|
||||||
@ -489,6 +491,7 @@ export interface BaseClientOptions {
|
|||||||
};
|
};
|
||||||
components?: {
|
components?: {
|
||||||
defaults?: {
|
defaults?: {
|
||||||
|
onBeforeMiddlewares?: ComponentCommand['onBeforeMiddlewares'];
|
||||||
onRunError?: ComponentCommand['onRunError'];
|
onRunError?: ComponentCommand['onRunError'];
|
||||||
onInternalError?: ComponentCommand['onInternalError'];
|
onInternalError?: ComponentCommand['onInternalError'];
|
||||||
onMiddlewaresError?: ComponentCommand['onMiddlewaresError'];
|
onMiddlewaresError?: ComponentCommand['onMiddlewaresError'];
|
||||||
@ -497,6 +500,7 @@ export interface BaseClientOptions {
|
|||||||
};
|
};
|
||||||
modals?: {
|
modals?: {
|
||||||
defaults?: {
|
defaults?: {
|
||||||
|
onBeforeMiddlewares?: ModalCommand['onBeforeMiddlewares'];
|
||||||
onRunError?: ModalCommand['onRunError'];
|
onRunError?: ModalCommand['onRunError'];
|
||||||
onInternalError?: ModalCommand['onInternalError'];
|
onInternalError?: ModalCommand['onInternalError'];
|
||||||
onMiddlewaresError?: ModalCommand['onMiddlewaresError'];
|
onMiddlewaresError?: ModalCommand['onMiddlewaresError'];
|
||||||
|
@ -285,6 +285,8 @@ export class BaseCommand {
|
|||||||
Object.setPrototypeOf(this, __tempCommand.prototype);
|
Object.setPrototypeOf(this, __tempCommand.prototype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBeforeMiddlewares?(context: CommandContext): any;
|
||||||
|
onBeforeOptions?(context: CommandContext): any;
|
||||||
run?(context: CommandContext): any;
|
run?(context: CommandContext): any;
|
||||||
onAfterRun?(context: CommandContext, error: unknown | undefined): any;
|
onAfterRun?(context: CommandContext, error: unknown | undefined): any;
|
||||||
onRunError?(context: CommandContext, error: unknown): any;
|
onRunError?(context: CommandContext, error: unknown): any;
|
||||||
|
@ -54,6 +54,7 @@ export abstract class EntryPointCommand {
|
|||||||
Object.setPrototypeOf(this, __tempCommand.prototype);
|
Object.setPrototypeOf(this, __tempCommand.prototype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBeforeMiddlewares?(context: EntryPointContext): any;
|
||||||
abstract run?(context: EntryPointContext): any;
|
abstract run?(context: EntryPointContext): any;
|
||||||
onAfterRun?(context: EntryPointContext, error: unknown | undefined): any;
|
onAfterRun?(context: EntryPointContext, error: unknown | undefined): any;
|
||||||
onRunError(context: EntryPointContext<never>, error: unknown): any {
|
onRunError(context: EntryPointContext<never>, error: unknown): any {
|
||||||
|
@ -53,6 +53,7 @@ export abstract class ContextMenuCommand {
|
|||||||
Object.setPrototypeOf(this, __tempCommand.prototype);
|
Object.setPrototypeOf(this, __tempCommand.prototype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBeforeMiddlewares?(context: MenuCommandContext<any>): any;
|
||||||
abstract run?(context: MenuCommandContext<any>): any;
|
abstract run?(context: MenuCommandContext<any>): any;
|
||||||
onAfterRun?(context: MenuCommandContext<any>, error: unknown | undefined): any;
|
onAfterRun?(context: MenuCommandContext<any>, error: unknown | undefined): any;
|
||||||
onRunError?(context: MenuCommandContext<any, never>, error: unknown): any;
|
onRunError?(context: MenuCommandContext<any, never>, error: unknown): any;
|
||||||
|
@ -91,7 +91,7 @@ export class HandleCommand {
|
|||||||
await optionsResolver.getCommand()?.onInternalError?.(this.client, optionsResolver.getCommand()!, error);
|
await optionsResolver.getCommand()?.onInternalError?.(this.client, optionsResolver.getCommand()!, error);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// pass
|
this.client.logger.error(`[${optionsResolver.fullCommandName}] Internal error:`, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,17 +100,18 @@ export class HandleCommand {
|
|||||||
interaction: MessageCommandInteraction | UserCommandInteraction,
|
interaction: MessageCommandInteraction | UserCommandInteraction,
|
||||||
context: MenuCommandContext<MessageCommandInteraction | UserCommandInteraction>,
|
context: MenuCommandContext<MessageCommandInteraction | UserCommandInteraction>,
|
||||||
) {
|
) {
|
||||||
if (context.guildId && command.botPermissions) {
|
|
||||||
const permissions = this.checkPermissions(interaction.appPermissions, command.botPermissions);
|
|
||||||
if (permissions) return command.onBotPermissionsFail?.(context, permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
const resultGlobal = await this.runGlobalMiddlewares(command, context);
|
|
||||||
if (typeof resultGlobal === 'boolean') return;
|
|
||||||
const resultMiddle = await this.runMiddlewares(command, context);
|
|
||||||
if (typeof resultMiddle === 'boolean') return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (context.guildId && command.botPermissions) {
|
||||||
|
const permissions = this.checkPermissions(interaction.appPermissions, command.botPermissions);
|
||||||
|
if (permissions) return await command.onBotPermissionsFail?.(context, permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
await command.onBeforeMiddlewares?.(context);
|
||||||
|
const resultGlobal = await this.runGlobalMiddlewares(command, context);
|
||||||
|
if (typeof resultGlobal === 'boolean') return;
|
||||||
|
const resultMiddle = await this.runMiddlewares(command, context);
|
||||||
|
if (typeof resultMiddle === 'boolean') return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await command.run!(context);
|
await command.run!(context);
|
||||||
await command.onAfterRun?.(context, undefined);
|
await command.onAfterRun?.(context, undefined);
|
||||||
@ -121,8 +122,8 @@ export class HandleCommand {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
try {
|
try {
|
||||||
await command.onInternalError?.(this.client, command, error);
|
await command.onInternalError?.(this.client, command, error);
|
||||||
} catch {
|
} catch (err) {
|
||||||
// pass
|
this.client.logger.error(`[${command.name}] Internal error:`, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,17 +145,18 @@ export class HandleCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async entryPoint(command: EntryPointCommand, interaction: EntryPointInteraction, context: EntryPointContext) {
|
async entryPoint(command: EntryPointCommand, interaction: EntryPointInteraction, context: EntryPointContext) {
|
||||||
if (context.guildId && command.botPermissions) {
|
|
||||||
const permissions = this.checkPermissions(interaction.appPermissions, command.botPermissions);
|
|
||||||
if (permissions) return command.onBotPermissionsFail(context, permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
const resultGlobal = await this.runGlobalMiddlewares(command, context);
|
|
||||||
if (typeof resultGlobal === 'boolean') return;
|
|
||||||
const resultMiddle = await this.runMiddlewares(command, context);
|
|
||||||
if (typeof resultMiddle === 'boolean') return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (context.guildId && command.botPermissions) {
|
||||||
|
const permissions = this.checkPermissions(interaction.appPermissions, command.botPermissions);
|
||||||
|
if (permissions) return await command.onBotPermissionsFail(context, permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
await command.onBeforeMiddlewares?.(context);
|
||||||
|
const resultGlobal = await this.runGlobalMiddlewares(command, context);
|
||||||
|
if (typeof resultGlobal === 'boolean') return;
|
||||||
|
const resultMiddle = await this.runMiddlewares(command, context);
|
||||||
|
if (typeof resultMiddle === 'boolean') return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await command.run!(context);
|
await command.run!(context);
|
||||||
await command.onAfterRun?.(context, undefined);
|
await command.onAfterRun?.(context, undefined);
|
||||||
@ -165,8 +167,8 @@ export class HandleCommand {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
try {
|
try {
|
||||||
await command.onInternalError(this.client, command, error);
|
await command.onInternalError(this.client, command, error);
|
||||||
} catch {
|
} catch (err) {
|
||||||
// pass
|
this.client.logger.error(`[${command.name}] Internal error:`, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,26 +179,28 @@ export class HandleCommand {
|
|||||||
resolver: OptionResolverStructure,
|
resolver: OptionResolverStructure,
|
||||||
context: CommandContext,
|
context: CommandContext,
|
||||||
) {
|
) {
|
||||||
if (context.guildId) {
|
|
||||||
if (command.botPermissions) {
|
|
||||||
const permissions = this.checkPermissions(interaction.appPermissions, command.botPermissions);
|
|
||||||
if (permissions) return command.onBotPermissionsFail?.(context, permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command.defaultMemberPermissions) {
|
|
||||||
const permissions = this.checkPermissions(interaction.member!.permissions, command.defaultMemberPermissions);
|
|
||||||
if (permissions) return command.onPermissionsFail?.(context, permissions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(await this.runOptions(command, context, resolver))) return;
|
|
||||||
|
|
||||||
const resultGlobal = await this.runGlobalMiddlewares(command, context);
|
|
||||||
if (typeof resultGlobal === 'boolean') return;
|
|
||||||
const resultMiddle = await this.runMiddlewares(command, context);
|
|
||||||
if (typeof resultMiddle === 'boolean') return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (context.guildId) {
|
||||||
|
if (command.botPermissions) {
|
||||||
|
const permissions = this.checkPermissions(interaction.appPermissions, command.botPermissions);
|
||||||
|
if (permissions) return await command.onBotPermissionsFail?.(context, permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.defaultMemberPermissions) {
|
||||||
|
const permissions = this.checkPermissions(interaction.member!.permissions, command.defaultMemberPermissions);
|
||||||
|
if (permissions) return await command.onPermissionsFail?.(context, permissions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await command.onBeforeOptions?.(context);
|
||||||
|
if (!(await this.runOptions(command, context, resolver))) return;
|
||||||
|
|
||||||
|
await command.onBeforeMiddlewares?.(context);
|
||||||
|
const resultGlobal = await this.runGlobalMiddlewares(command, context);
|
||||||
|
if (typeof resultGlobal === 'boolean') return;
|
||||||
|
const resultMiddle = await this.runMiddlewares(command, context);
|
||||||
|
if (typeof resultMiddle === 'boolean') return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await command.run!(context);
|
await command.run!(context);
|
||||||
await command.onAfterRun?.(context, undefined);
|
await command.onAfterRun?.(context, undefined);
|
||||||
@ -207,8 +211,8 @@ export class HandleCommand {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
try {
|
try {
|
||||||
await command.onInternalError?.(this.client, command, error);
|
await command.onInternalError?.(this.client, command, error);
|
||||||
} catch {
|
} catch (err) {
|
||||||
// pass
|
this.client.logger.error(`[${command.name}] Internal error:`, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -350,17 +354,17 @@ export class HandleCommand {
|
|||||||
attachments: {},
|
attachments: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const args = this.argsParser(argsContent, command, message);
|
|
||||||
const { options, errors } = await this.argsOptionsParser(command, rawMessage, args, resolved);
|
|
||||||
const optionsResolver = this.makeResolver(self, options, parent as Command, rawMessage.guild_id, resolved);
|
|
||||||
const context = new CommandContext(self, message, optionsResolver, shardId, command);
|
|
||||||
//@ts-expect-error
|
|
||||||
const extendContext = self.options?.context?.(message) ?? {};
|
|
||||||
Object.assign(context, extendContext);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const args = this.argsParser(argsContent, command, message);
|
||||||
|
const { options, errors } = await this.argsOptionsParser(command, rawMessage, args, resolved);
|
||||||
|
const optionsResolver = this.makeResolver(self, options, parent as Command, rawMessage.guild_id, resolved);
|
||||||
|
const context = new CommandContext(self, message, optionsResolver, shardId, command);
|
||||||
|
//@ts-expect-error
|
||||||
|
const extendContext = self.options?.context?.(message) ?? {};
|
||||||
|
Object.assign(context, extendContext);
|
||||||
|
|
||||||
if (errors.length) {
|
if (errors.length) {
|
||||||
return command.onOptionsError?.(
|
return await command.onOptionsError?.(
|
||||||
context,
|
context,
|
||||||
Object.fromEntries(
|
Object.fromEntries(
|
||||||
errors.map(x => {
|
errors.map(x => {
|
||||||
@ -383,7 +387,7 @@ export class HandleCommand {
|
|||||||
const permissions = this.checkPermissions(memberPermissions, command.defaultMemberPermissions);
|
const permissions = this.checkPermissions(memberPermissions, command.defaultMemberPermissions);
|
||||||
const guild = await this.client.guilds.raw(rawMessage.guild_id);
|
const guild = await this.client.guilds.raw(rawMessage.guild_id);
|
||||||
if (permissions && guild.owner_id !== rawMessage.author.id) {
|
if (permissions && guild.owner_id !== rawMessage.author.id) {
|
||||||
return command.onPermissionsFail?.(context, memberPermissions.keys(permissions));
|
return await command.onPermissionsFail?.(context, memberPermissions.keys(permissions));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,13 +395,15 @@ export class HandleCommand {
|
|||||||
const appPermissions = await self.members.permissions(rawMessage.guild_id, self.botId);
|
const appPermissions = await self.members.permissions(rawMessage.guild_id, self.botId);
|
||||||
const permissions = this.checkPermissions(appPermissions, command.botPermissions);
|
const permissions = this.checkPermissions(appPermissions, command.botPermissions);
|
||||||
if (permissions) {
|
if (permissions) {
|
||||||
return command.onBotPermissionsFail?.(context, permissions);
|
return await command.onBotPermissionsFail?.(context, permissions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await command.onBeforeOptions?.(context);
|
||||||
if (!(await this.runOptions(command, context, optionsResolver))) return;
|
if (!(await this.runOptions(command, context, optionsResolver))) return;
|
||||||
|
|
||||||
|
await command.onBeforeMiddlewares?.(context);
|
||||||
const resultGlobal = await this.runGlobalMiddlewares(command, context);
|
const resultGlobal = await this.runGlobalMiddlewares(command, context);
|
||||||
if (typeof resultGlobal === 'boolean') return;
|
if (typeof resultGlobal === 'boolean') return;
|
||||||
const resultMiddle = await this.runMiddlewares(command, context);
|
const resultMiddle = await this.runMiddlewares(command, context);
|
||||||
@ -412,8 +418,8 @@ export class HandleCommand {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
try {
|
try {
|
||||||
await command.onInternalError?.(this.client, command, error);
|
await command.onInternalError?.(this.client, command, error);
|
||||||
} catch {
|
} catch (err) {
|
||||||
// http 418
|
this.client.logger.error(`[${command.name}] Internal error:`, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -574,8 +580,8 @@ export class HandleCommand {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
try {
|
try {
|
||||||
await command.onInternalError?.(this.client, command as never, e);
|
await command.onInternalError?.(this.client, command as never, e);
|
||||||
} catch {
|
} catch (err) {
|
||||||
// http 418
|
this.client.logger.error(`[${command.name}] Internal error:`, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -602,8 +608,8 @@ export class HandleCommand {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
try {
|
try {
|
||||||
await command.onInternalError?.(this.client, command as never, e);
|
await command.onInternalError?.(this.client, command as never, e);
|
||||||
} catch {
|
} catch (err) {
|
||||||
// http 418
|
this.client.logger.error(`[${command.name}] Internal error:`, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -627,15 +633,7 @@ export class HandleCommand {
|
|||||||
async runOptions(command: Command | SubCommand, context: CommandContext, resolver: OptionResolverStructure) {
|
async runOptions(command: Command | SubCommand, context: CommandContext, resolver: OptionResolverStructure) {
|
||||||
const [erroredOptions, result] = await command.__runOptions(context, resolver);
|
const [erroredOptions, result] = await command.__runOptions(context, resolver);
|
||||||
if (erroredOptions) {
|
if (erroredOptions) {
|
||||||
try {
|
await command.onOptionsError?.(context, result);
|
||||||
await command.onOptionsError?.(context, result);
|
|
||||||
} catch (e) {
|
|
||||||
try {
|
|
||||||
await command.onInternalError?.(this.client, command, e);
|
|
||||||
} catch {
|
|
||||||
// http 418
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -466,6 +466,8 @@ export class CommandHandler extends BaseHandler {
|
|||||||
|
|
||||||
stablishContextCommandDefaults(commandInstance: InstanceType<HandleableCommand>): ContextMenuCommand | false {
|
stablishContextCommandDefaults(commandInstance: InstanceType<HandleableCommand>): ContextMenuCommand | false {
|
||||||
if (!(commandInstance instanceof ContextMenuCommand)) return false;
|
if (!(commandInstance instanceof ContextMenuCommand)) return false;
|
||||||
|
commandInstance.onBeforeMiddlewares ??= this.client.options.commands?.defaults?.onBeforeMiddlewares;
|
||||||
|
|
||||||
commandInstance.onAfterRun ??= this.client.options.commands?.defaults?.onAfterRun;
|
commandInstance.onAfterRun ??= this.client.options.commands?.defaults?.onAfterRun;
|
||||||
|
|
||||||
commandInstance.onBotPermissionsFail ??= this.client.options.commands?.defaults?.onBotPermissionsFail;
|
commandInstance.onBotPermissionsFail ??= this.client.options.commands?.defaults?.onBotPermissionsFail;
|
||||||
@ -482,6 +484,8 @@ export class CommandHandler extends BaseHandler {
|
|||||||
commandInstance: InstanceType<HandleableCommand>,
|
commandInstance: InstanceType<HandleableCommand>,
|
||||||
): OmitInsert<Command, 'options', { options: NonNullable<Command['options']> }> | false {
|
): OmitInsert<Command, 'options', { options: NonNullable<Command['options']> }> | false {
|
||||||
if (!(commandInstance instanceof Command)) return false;
|
if (!(commandInstance instanceof Command)) return false;
|
||||||
|
commandInstance.onBeforeMiddlewares ??= this.client.options.commands?.defaults?.onBeforeMiddlewares;
|
||||||
|
commandInstance.onBeforeOptions ??= this.client.options.commands?.defaults?.onBeforeOptions;
|
||||||
commandInstance.onAfterRun ??= this.client.options.commands?.defaults?.onAfterRun;
|
commandInstance.onAfterRun ??= this.client.options.commands?.defaults?.onAfterRun;
|
||||||
commandInstance.onBotPermissionsFail ??= this.client.options.commands?.defaults?.onBotPermissionsFail;
|
commandInstance.onBotPermissionsFail ??= this.client.options.commands?.defaults?.onBotPermissionsFail;
|
||||||
commandInstance.onInternalError ??= this.client.options.commands?.defaults?.onInternalError;
|
commandInstance.onInternalError ??= this.client.options.commands?.defaults?.onInternalError;
|
||||||
@ -495,6 +499,14 @@ export class CommandHandler extends BaseHandler {
|
|||||||
|
|
||||||
stablishSubCommandDefaults(commandInstance: Command, option: SubCommand): SubCommand {
|
stablishSubCommandDefaults(commandInstance: Command, option: SubCommand): SubCommand {
|
||||||
option.middlewares = (commandInstance.middlewares ?? []).concat(option.middlewares ?? []);
|
option.middlewares = (commandInstance.middlewares ?? []).concat(option.middlewares ?? []);
|
||||||
|
option.onBeforeMiddlewares =
|
||||||
|
option.onBeforeMiddlewares?.bind(option) ??
|
||||||
|
commandInstance.onBeforeMiddlewares?.bind(commandInstance) ??
|
||||||
|
this.client.options.commands?.defaults?.onBeforeMiddlewares;
|
||||||
|
option.onBeforeOptions =
|
||||||
|
option.onBeforeOptions?.bind(option) ??
|
||||||
|
commandInstance.onBeforeOptions?.bind(commandInstance) ??
|
||||||
|
this.client.options.commands?.defaults?.onBeforeOptions;
|
||||||
option.onMiddlewaresError =
|
option.onMiddlewaresError =
|
||||||
option.onMiddlewaresError?.bind(option) ??
|
option.onMiddlewaresError?.bind(option) ??
|
||||||
commandInstance.onMiddlewaresError?.bind(commandInstance) ??
|
commandInstance.onMiddlewaresError?.bind(commandInstance) ??
|
||||||
|
@ -1,20 +1,11 @@
|
|||||||
import type { RawFile } from '../../api';
|
import type { RawFile } from '../../api';
|
||||||
|
import type { Attachment, AttachmentBuilder, Embed, Modal, PollBuilder, TopLevelBuilders } from '../../builders';
|
||||||
import type {
|
import type {
|
||||||
ActionRow,
|
|
||||||
Attachment,
|
|
||||||
AttachmentBuilder,
|
|
||||||
BuilderComponents,
|
|
||||||
Embed,
|
|
||||||
Modal,
|
|
||||||
PollBuilder,
|
|
||||||
} from '../../builders';
|
|
||||||
import type {
|
|
||||||
APIActionRowComponent,
|
|
||||||
APIEmbed,
|
APIEmbed,
|
||||||
APIInteractionResponseCallbackData,
|
APIInteractionResponseCallbackData,
|
||||||
APIInteractionResponseChannelMessageWithSource,
|
APIInteractionResponseChannelMessageWithSource,
|
||||||
APIMessageActionRowComponent,
|
|
||||||
APIModalInteractionResponse,
|
APIModalInteractionResponse,
|
||||||
|
MessageFlags,
|
||||||
RESTAPIPollCreate,
|
RESTAPIPollCreate,
|
||||||
RESTPatchAPIChannelMessageJSONBody,
|
RESTPatchAPIChannelMessageJSONBody,
|
||||||
RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
||||||
@ -26,7 +17,7 @@ import type { OmitInsert } from './util';
|
|||||||
|
|
||||||
export interface ResolverProps {
|
export interface ResolverProps {
|
||||||
embeds?: Embed[] | APIEmbed[] | undefined;
|
embeds?: Embed[] | APIEmbed[] | undefined;
|
||||||
components?: APIActionRowComponent<APIMessageActionRowComponent>[] | ActionRow<BuilderComponents>[] | undefined;
|
components?: TopLevelBuilders[];
|
||||||
files?: AttachmentBuilder[] | Attachment[] | RawFile[] | undefined;
|
files?: AttachmentBuilder[] | Attachment[] | RawFile[] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +53,9 @@ export type InteractionMessageUpdateBodyRequest = OmitInsert<
|
|||||||
RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
||||||
'components' | 'embeds' | 'poll',
|
'components' | 'embeds' | 'poll',
|
||||||
SendResolverProps
|
SendResolverProps
|
||||||
>;
|
> & {
|
||||||
|
flags?: MessageFlags;
|
||||||
|
};
|
||||||
|
|
||||||
export type ComponentInteractionMessageUpdate = OmitInsert<
|
export type ComponentInteractionMessageUpdate = OmitInsert<
|
||||||
APIInteractionResponseCallbackData,
|
APIInteractionResponseCallbackData,
|
||||||
|
@ -4,7 +4,7 @@ import type { ActionRowMessageComponents } from './index';
|
|||||||
import { componentFactory } from './index';
|
import { componentFactory } from './index';
|
||||||
|
|
||||||
export class MessageActionRowComponent<
|
export class MessageActionRowComponent<
|
||||||
T extends ActionRowMessageComponents,
|
T extends ActionRowMessageComponents = ActionRowMessageComponents,
|
||||||
> extends BaseComponent<ComponentType.ActionRow> {
|
> extends BaseComponent<ComponentType.ActionRow> {
|
||||||
private ComponentsFactory: T[];
|
private ComponentsFactory: T[];
|
||||||
constructor(data: {
|
constructor(data: {
|
||||||
|
@ -1,13 +1,37 @@
|
|||||||
import { fromComponent } from '../builders';
|
import {
|
||||||
|
type ActionRow,
|
||||||
|
type Button,
|
||||||
|
type ChannelSelectMenu,
|
||||||
|
type Container,
|
||||||
|
type File,
|
||||||
|
type MediaGallery,
|
||||||
|
type MentionableSelectMenu,
|
||||||
|
type RoleSelectMenu,
|
||||||
|
type Section,
|
||||||
|
type Separator,
|
||||||
|
type StringSelectMenu,
|
||||||
|
type TextDisplay,
|
||||||
|
type TextInput,
|
||||||
|
type Thumbnail,
|
||||||
|
type UserSelectMenu,
|
||||||
|
fromComponent,
|
||||||
|
} from '../builders';
|
||||||
import {
|
import {
|
||||||
type APIActionRowComponent,
|
type APIActionRowComponent,
|
||||||
type APIActionRowComponentTypes,
|
type APIActionRowComponentTypes,
|
||||||
type APIButtonComponent,
|
type APIButtonComponent,
|
||||||
type APIChannelSelectComponent,
|
type APIChannelSelectComponent,
|
||||||
|
type APIContainerComponent,
|
||||||
|
type APIFileComponent,
|
||||||
|
type APIMediaGalleryComponent,
|
||||||
type APIMentionableSelectComponent,
|
type APIMentionableSelectComponent,
|
||||||
type APIRoleSelectComponent,
|
type APIRoleSelectComponent,
|
||||||
|
type APISectionComponent,
|
||||||
|
type APISeparatorComponent,
|
||||||
type APIStringSelectComponent,
|
type APIStringSelectComponent,
|
||||||
|
type APITextDispalyComponent,
|
||||||
type APITextInputComponent,
|
type APITextInputComponent,
|
||||||
|
type APIThumbnailComponent,
|
||||||
type APIUserSelectComponent,
|
type APIUserSelectComponent,
|
||||||
ComponentType,
|
ComponentType,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
@ -24,7 +48,7 @@ export class BaseComponent<T extends ComponentType> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toBuilder() {
|
toBuilder() {
|
||||||
return fromComponent(this.data);
|
return fromComponent(this.data) as BuilderComponentsMap[T];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export interface APIComponentsMap {
|
export interface APIComponentsMap {
|
||||||
@ -36,4 +60,29 @@ export interface APIComponentsMap {
|
|||||||
[ComponentType.StringSelect]: APIStringSelectComponent;
|
[ComponentType.StringSelect]: APIStringSelectComponent;
|
||||||
[ComponentType.UserSelect]: APIUserSelectComponent;
|
[ComponentType.UserSelect]: APIUserSelectComponent;
|
||||||
[ComponentType.TextInput]: APITextInputComponent;
|
[ComponentType.TextInput]: APITextInputComponent;
|
||||||
|
[ComponentType.File]: APIFileComponent;
|
||||||
|
[ComponentType.Thumbnail]: APIThumbnailComponent;
|
||||||
|
[ComponentType.Section]: APISectionComponent;
|
||||||
|
[ComponentType.Container]: APIContainerComponent;
|
||||||
|
[ComponentType.MediaGallery]: APIMediaGalleryComponent;
|
||||||
|
[ComponentType.Separator]: APISeparatorComponent;
|
||||||
|
[ComponentType.TextDisplay]: APITextDispalyComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BuilderComponentsMap {
|
||||||
|
[ComponentType.ActionRow]: ActionRow;
|
||||||
|
[ComponentType.Button]: Button;
|
||||||
|
[ComponentType.ChannelSelect]: ChannelSelectMenu;
|
||||||
|
[ComponentType.MentionableSelect]: MentionableSelectMenu;
|
||||||
|
[ComponentType.RoleSelect]: RoleSelectMenu;
|
||||||
|
[ComponentType.StringSelect]: StringSelectMenu;
|
||||||
|
[ComponentType.UserSelect]: UserSelectMenu;
|
||||||
|
[ComponentType.TextInput]: TextInput;
|
||||||
|
[ComponentType.File]: File;
|
||||||
|
[ComponentType.Thumbnail]: Thumbnail;
|
||||||
|
[ComponentType.Section]: Section;
|
||||||
|
[ComponentType.Container]: Container;
|
||||||
|
[ComponentType.MediaGallery]: MediaGallery;
|
||||||
|
[ComponentType.Separator]: Separator;
|
||||||
|
[ComponentType.TextDisplay]: TextDisplay;
|
||||||
}
|
}
|
||||||
|
23
src/components/Container.ts
Normal file
23
src/components/Container.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { type ContainerComponents, componentFactory } from '.';
|
||||||
|
import type { APIContainerComponent, ComponentType } from '../types';
|
||||||
|
import { BaseComponent } from './BaseComponent';
|
||||||
|
|
||||||
|
export class ContainerComponent extends BaseComponent<ComponentType.Container> {
|
||||||
|
_components: ContainerComponents[];
|
||||||
|
constructor(data: APIContainerComponent) {
|
||||||
|
super(data);
|
||||||
|
this._components = this.data.components.map(componentFactory) as ContainerComponents[];
|
||||||
|
}
|
||||||
|
|
||||||
|
get components() {
|
||||||
|
return this.data.components;
|
||||||
|
}
|
||||||
|
|
||||||
|
get accentColor() {
|
||||||
|
return this.data.accent_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
get spoiler() {
|
||||||
|
return this.data.spoiler;
|
||||||
|
}
|
||||||
|
}
|
16
src/components/File.ts
Normal file
16
src/components/File.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import type { ComponentType } from '../types';
|
||||||
|
import { BaseComponent } from './BaseComponent';
|
||||||
|
|
||||||
|
export class FileComponent extends BaseComponent<ComponentType.File> {
|
||||||
|
get spoiler() {
|
||||||
|
return this.data.spoiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
get file() {
|
||||||
|
return this.data.file;
|
||||||
|
}
|
||||||
|
|
||||||
|
get id() {
|
||||||
|
return this.data.id;
|
||||||
|
}
|
||||||
|
}
|
12
src/components/MediaGallery.ts
Normal file
12
src/components/MediaGallery.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import type { ComponentType } from '../types';
|
||||||
|
import { BaseComponent } from './BaseComponent';
|
||||||
|
|
||||||
|
export class MediaGalleryComponent extends BaseComponent<ComponentType.MediaGallery> {
|
||||||
|
get items() {
|
||||||
|
return this.data.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
get id() {
|
||||||
|
return this.data.id;
|
||||||
|
}
|
||||||
|
}
|
23
src/components/Section.ts
Normal file
23
src/components/Section.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { componentFactory } from '.';
|
||||||
|
import type { APISectionComponent, ComponentType } from '../types';
|
||||||
|
import { BaseComponent } from './BaseComponent';
|
||||||
|
import type { ButtonComponent } from './ButtonComponent';
|
||||||
|
import type { TextDisplayComponent } from './TextDisplay';
|
||||||
|
import type { ThumbnailComponent } from './Thumbnail';
|
||||||
|
|
||||||
|
export class SectionComponent extends BaseComponent<ComponentType.Section> {
|
||||||
|
protected _components: TextDisplayComponent[];
|
||||||
|
protected _accessory: ThumbnailComponent | ButtonComponent;
|
||||||
|
constructor(data: APISectionComponent) {
|
||||||
|
super(data);
|
||||||
|
this._components = data.components?.map(componentFactory) as TextDisplayComponent[];
|
||||||
|
this._accessory = componentFactory(data.accessory) as ThumbnailComponent | ButtonComponent;
|
||||||
|
}
|
||||||
|
get components() {
|
||||||
|
return this._components;
|
||||||
|
}
|
||||||
|
|
||||||
|
get accessory() {
|
||||||
|
return this._accessory;
|
||||||
|
}
|
||||||
|
}
|
16
src/components/Separator.ts
Normal file
16
src/components/Separator.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import type { ComponentType } from '../types';
|
||||||
|
import { BaseComponent } from './BaseComponent';
|
||||||
|
|
||||||
|
export class SeparatorComponent extends BaseComponent<ComponentType.Separator> {
|
||||||
|
get id() {
|
||||||
|
return this.data.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
get spacing() {
|
||||||
|
return this.data.spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
get divider() {
|
||||||
|
return this.data.divider;
|
||||||
|
}
|
||||||
|
}
|
8
src/components/TextDisplay.ts
Normal file
8
src/components/TextDisplay.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import type { ComponentType } from '../types';
|
||||||
|
import { BaseComponent } from './BaseComponent';
|
||||||
|
|
||||||
|
export class TextDisplayComponent extends BaseComponent<ComponentType.TextDisplay> {
|
||||||
|
get content() {
|
||||||
|
return this.data.content;
|
||||||
|
}
|
||||||
|
}
|
20
src/components/Thumbnail.ts
Normal file
20
src/components/Thumbnail.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import type { ComponentType } from '../types';
|
||||||
|
import { BaseComponent } from './BaseComponent';
|
||||||
|
|
||||||
|
export class ThumbnailComponent extends BaseComponent<ComponentType.Thumbnail> {
|
||||||
|
get id() {
|
||||||
|
return this.data.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
get media() {
|
||||||
|
return this.data.media;
|
||||||
|
}
|
||||||
|
|
||||||
|
get description() {
|
||||||
|
return this.data.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
get spoiler() {
|
||||||
|
return this.data.spoiler;
|
||||||
|
}
|
||||||
|
}
|
@ -33,6 +33,7 @@ export abstract class ComponentCommand {
|
|||||||
return ComponentType[this.componentType];
|
return ComponentType[this.componentType];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBeforeMiddlewares?(context: ComponentContext): any;
|
||||||
onAfterRun?(context: ComponentContext, error: unknown | undefined): any;
|
onAfterRun?(context: ComponentContext, error: unknown | undefined): any;
|
||||||
onRunError?(context: ComponentContext, error: unknown): any;
|
onRunError?(context: ComponentContext, error: unknown): any;
|
||||||
onMiddlewaresError?(context: ComponentContext, error: string): any;
|
onMiddlewaresError?(context: ComponentContext, error: string): any;
|
||||||
|
@ -204,6 +204,7 @@ export class ComponentHandler extends BaseHandler {
|
|||||||
component.onMiddlewaresError ??= this.client.options?.[is]?.defaults?.onMiddlewaresError;
|
component.onMiddlewaresError ??= this.client.options?.[is]?.defaults?.onMiddlewaresError;
|
||||||
component.onRunError ??= this.client.options?.[is]?.defaults?.onRunError;
|
component.onRunError ??= this.client.options?.[is]?.defaults?.onRunError;
|
||||||
component.onAfterRun ??= this.client.options?.[is]?.defaults?.onAfterRun;
|
component.onAfterRun ??= this.client.options?.[is]?.defaults?.onAfterRun;
|
||||||
|
component.onBeforeMiddlewares ??= this.client.options?.[is]?.defaults?.onBeforeMiddlewares;
|
||||||
}
|
}
|
||||||
|
|
||||||
set(instances: (new () => ComponentCommands)[]) {
|
set(instances: (new () => ComponentCommands)[]) {
|
||||||
@ -289,6 +290,7 @@ export class ComponentHandler extends BaseHandler {
|
|||||||
|
|
||||||
async execute(i: ComponentCommands, context: ComponentContext | ModalContext) {
|
async execute(i: ComponentCommands, context: ComponentContext | ModalContext) {
|
||||||
try {
|
try {
|
||||||
|
await i.onBeforeMiddlewares?.(context as never);
|
||||||
const resultRunGlobalMiddlewares = await BaseCommand.__runMiddlewares(
|
const resultRunGlobalMiddlewares = await BaseCommand.__runMiddlewares(
|
||||||
context,
|
context,
|
||||||
(context.client.options?.globalMiddlewares ?? []) as keyof RegisteredMiddlewares,
|
(context.client.options?.globalMiddlewares ?? []) as keyof RegisteredMiddlewares,
|
||||||
@ -298,7 +300,7 @@ export class ComponentHandler extends BaseHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ('error' in resultRunGlobalMiddlewares) {
|
if ('error' in resultRunGlobalMiddlewares) {
|
||||||
return i.onMiddlewaresError?.(context as never, resultRunGlobalMiddlewares.error ?? 'Unknown error');
|
return await i.onMiddlewaresError?.(context as never, resultRunGlobalMiddlewares.error ?? 'Unknown error');
|
||||||
}
|
}
|
||||||
|
|
||||||
const resultRunMiddlewares = await BaseCommand.__runMiddlewares(context, i.middlewares, false);
|
const resultRunMiddlewares = await BaseCommand.__runMiddlewares(context, i.middlewares, false);
|
||||||
@ -306,7 +308,7 @@ export class ComponentHandler extends BaseHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ('error' in resultRunMiddlewares) {
|
if ('error' in resultRunMiddlewares) {
|
||||||
return i.onMiddlewaresError?.(context as never, resultRunMiddlewares.error ?? 'Unknown error');
|
return await i.onMiddlewaresError?.(context as never, resultRunMiddlewares.error ?? 'Unknown error');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -319,9 +321,8 @@ export class ComponentHandler extends BaseHandler {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
try {
|
try {
|
||||||
await i.onInternalError?.(this.client, error);
|
await i.onInternalError?.(this.client, error);
|
||||||
} catch (e) {
|
} catch (err) {
|
||||||
// supress error
|
this.client.logger.error(`[${i.customId ?? 'Component/Modal command'}] Internal error:`, err);
|
||||||
this.logger.error(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
import { type APIMessageActionRowComponent, ButtonStyle, ComponentType } from '../types';
|
import { type APIComponents, type APITopLevelComponent, ButtonStyle, ComponentType } from '../types';
|
||||||
|
import { MessageActionRowComponent } from './ActionRow';
|
||||||
import { BaseComponent } from './BaseComponent';
|
import { BaseComponent } from './BaseComponent';
|
||||||
import { ButtonComponent, LinkButtonComponent, SKUButtonComponent } from './ButtonComponent';
|
import { ButtonComponent, LinkButtonComponent, SKUButtonComponent } from './ButtonComponent';
|
||||||
import { ChannelSelectMenuComponent } from './ChannelSelectMenuComponent';
|
import { ChannelSelectMenuComponent } from './ChannelSelectMenuComponent';
|
||||||
|
import { ContainerComponent } from './Container';
|
||||||
|
import { FileComponent } from './File';
|
||||||
|
import { MediaGalleryComponent } from './MediaGallery';
|
||||||
import { MentionableSelectMenuComponent } from './MentionableSelectMenuComponent';
|
import { MentionableSelectMenuComponent } from './MentionableSelectMenuComponent';
|
||||||
import { RoleSelectMenuComponent } from './RoleSelectMenuComponent';
|
import { RoleSelectMenuComponent } from './RoleSelectMenuComponent';
|
||||||
|
import { SectionComponent } from './Section';
|
||||||
|
import { SeparatorComponent } from './Separator';
|
||||||
import { StringSelectMenuComponent } from './StringSelectMenuComponent';
|
import { StringSelectMenuComponent } from './StringSelectMenuComponent';
|
||||||
import type { TextInputComponent } from './TextInputComponent';
|
import { TextDisplayComponent } from './TextDisplay';
|
||||||
|
import { TextInputComponent } from './TextInputComponent';
|
||||||
|
import { ThumbnailComponent } from './Thumbnail';
|
||||||
import { UserSelectMenuComponent } from './UserSelectMenuComponent';
|
import { UserSelectMenuComponent } from './UserSelectMenuComponent';
|
||||||
|
|
||||||
export type MessageComponents =
|
export type MessageComponents =
|
||||||
@ -21,20 +29,37 @@ export type MessageComponents =
|
|||||||
|
|
||||||
export type ActionRowMessageComponents = Exclude<MessageComponents, TextInputComponent>;
|
export type ActionRowMessageComponents = Exclude<MessageComponents, TextInputComponent>;
|
||||||
|
|
||||||
|
export type AllComponents = MessageComponents | TopLevelComponents | ContainerComponents | BaseComponent<ComponentType>;
|
||||||
|
|
||||||
export * from './componentcommand';
|
export * from './componentcommand';
|
||||||
export * from './componentcontext';
|
export * from './componentcontext';
|
||||||
export * from './modalcommand';
|
export * from './modalcommand';
|
||||||
export * from './modalcontext';
|
export * from './modalcontext';
|
||||||
|
|
||||||
|
export type TopLevelComponents =
|
||||||
|
| SectionComponent
|
||||||
|
| ActionRowMessageComponents
|
||||||
|
| TextDisplayComponent
|
||||||
|
| ContainerComponent
|
||||||
|
| FileComponent
|
||||||
|
| MediaGalleryComponent
|
||||||
|
| BaseComponent<APITopLevelComponent['type']>;
|
||||||
|
|
||||||
|
export type ContainerComponents =
|
||||||
|
| MessageActionRowComponent
|
||||||
|
| TextDisplayComponent
|
||||||
|
| MediaGalleryComponent
|
||||||
|
| SectionComponent
|
||||||
|
| SeparatorComponent
|
||||||
|
| FileComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a new component instance based on the component type.
|
* Return a new component instance based on the component type.
|
||||||
*
|
*
|
||||||
* @param component The component to create.
|
* @param component The component to create.
|
||||||
* @returns The component instance.
|
* @returns The component instance.
|
||||||
*/
|
*/
|
||||||
export function componentFactory(
|
export function componentFactory(component: APIComponents): AllComponents {
|
||||||
component: APIMessageActionRowComponent,
|
|
||||||
): ActionRowMessageComponents | BaseComponent<ActionRowMessageComponents['type']> {
|
|
||||||
switch (component.type) {
|
switch (component.type) {
|
||||||
case ComponentType.Button: {
|
case ComponentType.Button: {
|
||||||
if (component.style === ButtonStyle.Link) {
|
if (component.style === ButtonStyle.Link) {
|
||||||
@ -55,7 +80,25 @@ export function componentFactory(
|
|||||||
return new UserSelectMenuComponent(component);
|
return new UserSelectMenuComponent(component);
|
||||||
case ComponentType.MentionableSelect:
|
case ComponentType.MentionableSelect:
|
||||||
return new MentionableSelectMenuComponent(component);
|
return new MentionableSelectMenuComponent(component);
|
||||||
|
case ComponentType.ActionRow:
|
||||||
|
return new MessageActionRowComponent(component as any);
|
||||||
|
case ComponentType.Container:
|
||||||
|
return new ContainerComponent(component);
|
||||||
|
case ComponentType.File:
|
||||||
|
return new FileComponent(component);
|
||||||
|
case ComponentType.MediaGallery:
|
||||||
|
return new MediaGalleryComponent(component);
|
||||||
|
case ComponentType.Section:
|
||||||
|
return new SectionComponent(component);
|
||||||
|
case ComponentType.TextDisplay:
|
||||||
|
return new TextDisplayComponent(component);
|
||||||
|
case ComponentType.Separator:
|
||||||
|
return new SeparatorComponent(component);
|
||||||
|
case ComponentType.Thumbnail:
|
||||||
|
return new ThumbnailComponent(component);
|
||||||
|
case ComponentType.TextInput:
|
||||||
|
return new TextInputComponent(component);
|
||||||
default:
|
default:
|
||||||
return new BaseComponent<ActionRowMessageComponents['type']>(component);
|
return new BaseComponent<ComponentType>(component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ export abstract class ModalCommand {
|
|||||||
|
|
||||||
props!: ExtraProps;
|
props!: ExtraProps;
|
||||||
|
|
||||||
|
onBeforeMiddlewares?(context: ModalContext): any;
|
||||||
onAfterRun?(context: ModalContext, error: unknown | undefined): any;
|
onAfterRun?(context: ModalContext, error: unknown | undefined): any;
|
||||||
onRunError?(context: ModalContext, error: unknown): any;
|
onRunError?(context: ModalContext, error: unknown): any;
|
||||||
onMiddlewaresError?(context: ModalContext, error: string): any;
|
onMiddlewaresError?(context: ModalContext, error: string): any;
|
||||||
|
@ -148,6 +148,7 @@ export class BaseInteraction<
|
|||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
return {
|
return {
|
||||||
type: body.type,
|
type: body.type,
|
||||||
|
// @ts-expect-error
|
||||||
data: BaseInteraction.transformBody(body.data ?? {}, files, self),
|
data: BaseInteraction.transformBody(body.data ?? {}, files, self),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -330,7 +331,6 @@ export class BaseInteraction<
|
|||||||
case ApplicationCommandType.PrimaryEntryPoint:
|
case ApplicationCommandType.PrimaryEntryPoint:
|
||||||
return new EntryPointInteraction(client, gateway as APIEntryPointCommandInteraction, __reply);
|
return new EntryPointInteraction(client, gateway as APIEntryPointCommandInteraction, __reply);
|
||||||
}
|
}
|
||||||
// biome-ignore lint/suspicious/noFallthroughSwitchClause: bad interaction between biome and ts-server
|
|
||||||
case InteractionType.MessageComponent:
|
case InteractionType.MessageComponent:
|
||||||
switch (gateway.data.component_type) {
|
switch (gateway.data.component_type) {
|
||||||
case ComponentType.Button:
|
case ComponentType.Button:
|
||||||
@ -357,6 +357,8 @@ export class BaseInteraction<
|
|||||||
gateway as APIMessageComponentSelectMenuInteraction,
|
gateway as APIMessageComponentSelectMenuInteraction,
|
||||||
__reply,
|
__reply,
|
||||||
);
|
);
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
case InteractionType.ModalSubmit:
|
case InteractionType.ModalSubmit:
|
||||||
return new ModalSubmitInteraction(client, gateway);
|
return new ModalSubmitInteraction(client, gateway);
|
||||||
@ -488,8 +490,8 @@ export class Interaction<
|
|||||||
fetchReply?: FR,
|
fetchReply?: FR,
|
||||||
): Promise<WebhookMessageStructure> {
|
): Promise<WebhookMessageStructure> {
|
||||||
if (await this.replied) {
|
if (await this.replied) {
|
||||||
const { content, embeds, allowed_mentions, components, files, attachments, poll } = body;
|
const { content, embeds, allowed_mentions, components, files, attachments, poll, flags } = body;
|
||||||
return this.editResponse({ content, embeds, allowed_mentions, components, files, attachments, poll });
|
return this.editResponse({ content, embeds, allowed_mentions, components, files, attachments, poll, flags });
|
||||||
}
|
}
|
||||||
return this.write(body as InteractionCreateBodyRequest, fetchReply);
|
return this.write(body as InteractionCreateBodyRequest, fetchReply);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { type AllChannels, Embed, type ReturnCache } from '..';
|
import { type AllChannels, Embed, type ReturnCache, componentFactory } from '..';
|
||||||
import type { ListenerOptions } from '../builders';
|
import type { ListenerOptions } from '../builders';
|
||||||
import {
|
import {
|
||||||
type GuildMemberStructure,
|
type GuildMemberStructure,
|
||||||
@ -15,8 +15,7 @@ import { type ObjectToLower, toCamelCase } from '../common';
|
|||||||
import { Formatter } from '../common';
|
import { Formatter } from '../common';
|
||||||
import type { EmojiResolvable } from '../common/types/resolvables';
|
import type { EmojiResolvable } from '../common/types/resolvables';
|
||||||
import type { MessageCreateBodyRequest, MessageUpdateBodyRequest } from '../common/types/write';
|
import type { MessageCreateBodyRequest, MessageUpdateBodyRequest } from '../common/types/write';
|
||||||
import type { ActionRowMessageComponents } from '../components';
|
import type { TopLevelComponents } from '../components';
|
||||||
import { MessageActionRowComponent } from '../components/ActionRow';
|
|
||||||
import type {
|
import type {
|
||||||
APIChannelMention,
|
APIChannelMention,
|
||||||
APIEmbed,
|
APIEmbed,
|
||||||
@ -37,7 +36,7 @@ export interface BaseMessage
|
|||||||
guildId?: string;
|
guildId?: string;
|
||||||
author: UserStructure;
|
author: UserStructure;
|
||||||
member?: GuildMemberStructure;
|
member?: GuildMemberStructure;
|
||||||
components: MessageActionRowComponent<ActionRowMessageComponents>[];
|
components: TopLevelComponents[];
|
||||||
poll?: PollStructure;
|
poll?: PollStructure;
|
||||||
mentions: {
|
mentions: {
|
||||||
roles: string[];
|
roles: string[];
|
||||||
@ -55,7 +54,7 @@ export class BaseMessage extends DiscordBase {
|
|||||||
channels: data.mention_channels ?? [],
|
channels: data.mention_channels ?? [],
|
||||||
users: [],
|
users: [],
|
||||||
};
|
};
|
||||||
this.components = data.components?.map(x => new MessageActionRowComponent(x)) ?? [];
|
this.components = (data.components?.map(componentFactory) as TopLevelComponents[]) ?? [];
|
||||||
this.embeds = data.embeds.map(embed => new InMessageEmbed(embed));
|
this.embeds = data.embeds.map(embed => new InMessageEmbed(embed));
|
||||||
this.patch(data);
|
this.patch(data);
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,9 @@ import type {
|
|||||||
*/
|
*/
|
||||||
import type {
|
import type {
|
||||||
APIWebhook,
|
APIWebhook,
|
||||||
RESTGetAPIWebhookWithTokenMessageQuery,
|
|
||||||
RESTPatchAPIWebhookJSONBody,
|
RESTPatchAPIWebhookJSONBody,
|
||||||
RESTPatchAPIWebhookWithTokenJSONBody,
|
RESTPatchAPIWebhookWithTokenJSONBody,
|
||||||
|
RESTPatchAPIWebhookWithTokenMessageQuery,
|
||||||
RESTPostAPIWebhookWithTokenQuery,
|
RESTPostAPIWebhookWithTokenQuery,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import type { AllChannels } from './channels';
|
import type { AllChannels } from './channels';
|
||||||
@ -181,7 +181,7 @@ export class Webhook extends DiscordBase {
|
|||||||
/** Type definition for parameters of editing a message through a webhook. */
|
/** Type definition for parameters of editing a message through a webhook. */
|
||||||
export type MessageWebhookMethodEditParams = MessageWebhookPayload<
|
export type MessageWebhookMethodEditParams = MessageWebhookPayload<
|
||||||
MessageWebhookUpdateBodyRequest,
|
MessageWebhookUpdateBodyRequest,
|
||||||
{ messageId: string; query?: RESTGetAPIWebhookWithTokenMessageQuery }
|
{ messageId: string; query?: RESTPatchAPIWebhookWithTokenMessageQuery }
|
||||||
>;
|
>;
|
||||||
/** Type definition for parameters of writing a message through a webhook. */
|
/** Type definition for parameters of writing a message through a webhook. */
|
||||||
export type MessageWebhookMethodWriteParams = MessageWebhookPayload<
|
export type MessageWebhookMethodWriteParams = MessageWebhookPayload<
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Collection, Formatter, type RawFile, type ReturnCache } from '..';
|
import { Collection, Formatter, type RawFile, type ReturnCache } from '..';
|
||||||
import { ActionRow, Embed, PollBuilder, resolveAttachment } from '../builders';
|
import { Embed, PollBuilder, resolveAttachment } from '../builders';
|
||||||
import type { Overwrites } from '../cache/resources/overwrites';
|
import type { Overwrites } from '../cache/resources/overwrites';
|
||||||
import {
|
import {
|
||||||
type BaseChannelStructure,
|
type BaseChannelStructure,
|
||||||
@ -353,8 +353,8 @@ export class MessagesMethods extends DiscordBase {
|
|||||||
const payload = {
|
const payload = {
|
||||||
allowed_mentions: self.options?.allowedMentions,
|
allowed_mentions: self.options?.allowedMentions,
|
||||||
...body,
|
...body,
|
||||||
components: body.components?.map(x => (x instanceof ActionRow ? x.toJSON() : x)) ?? undefined,
|
embeds: body.embeds?.map(x => (x instanceof Embed ? x.toJSON() : x)),
|
||||||
embeds: body.embeds?.map(x => (x instanceof Embed ? x.toJSON() : x)) ?? undefined,
|
components: body.components?.map(x => ('toJSON' in x ? x.toJSON() : x)) ?? undefined,
|
||||||
poll: poll ? (poll instanceof PollBuilder ? poll.toJSON() : poll) : undefined,
|
poll: poll ? (poll instanceof PollBuilder ? poll.toJSON() : poll) : undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { Snowflake } from '../../index';
|
import type { ComponentType, Snowflake } from '../../index';
|
||||||
import type { ComponentType } from '../channel';
|
|
||||||
import type { APIBaseInteraction, InteractionType } from '../interactions';
|
import type { APIBaseInteraction, InteractionType } from '../interactions';
|
||||||
import type {
|
import type {
|
||||||
APIDMInteractionWrapper,
|
APIDMInteractionWrapper,
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import type { APIActionRowComponent, APIModalActionRowComponent } from '../channel';
|
|
||||||
import type {
|
import type {
|
||||||
|
APIActionRowComponent,
|
||||||
APIBaseInteraction,
|
APIBaseInteraction,
|
||||||
APIDMInteractionWrapper,
|
APIDMInteractionWrapper,
|
||||||
APIGuildInteractionWrapper,
|
APIGuildInteractionWrapper,
|
||||||
|
APIModalActionRowComponent,
|
||||||
ComponentType,
|
ComponentType,
|
||||||
InteractionType,
|
InteractionType,
|
||||||
} from '../index';
|
} from '../index';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { MakeRequired } from '../../../common';
|
import type { MakeRequired } from '../../../common';
|
||||||
import type { RESTPostAPIWebhookWithTokenJSONBody } from '../../index';
|
import type { RESTPostAPIWebhookWithTokenJSONBody } from '../../index';
|
||||||
import type { APIActionRowComponent, APIModalActionRowComponent } from '../channel';
|
|
||||||
import type { MessageFlags } from '../index';
|
import type { APIActionRowComponent, APIModalActionRowComponent, MessageFlags } from '../index';
|
||||||
import type { APIApplicationCommandOptionChoice } from './applicationCommands';
|
import type { APIApplicationCommandOptionChoice } from './applicationCommands';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,7 +3,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { PickRequired } from '../../common';
|
import type { PickRequired } from '../../common';
|
||||||
import type { ChannelType, OverwriteType, Permissions, Snowflake, VideoQualityMode } from '../index';
|
import type {
|
||||||
|
APITopLevelComponent,
|
||||||
|
ChannelFlags,
|
||||||
|
ChannelType,
|
||||||
|
OverwriteType,
|
||||||
|
Permissions,
|
||||||
|
Snowflake,
|
||||||
|
VideoQualityMode,
|
||||||
|
} from '../index';
|
||||||
import type { APIApplication } from './application';
|
import type { APIApplication } from './application';
|
||||||
import type { APIPartialEmoji } from './emoji';
|
import type { APIPartialEmoji } from './emoji';
|
||||||
import type { APIGuildMember } from './guild';
|
import type { APIGuildMember } from './guild';
|
||||||
@ -579,7 +587,7 @@ export interface APIMessage {
|
|||||||
*
|
*
|
||||||
* See https://support-dev.discord.com/hc/articles/4404772028055
|
* See https://support-dev.discord.com/hc/articles/4404772028055
|
||||||
*/
|
*/
|
||||||
components?: APIActionRowComponent<APIMessageActionRowComponent>[];
|
components?: APITopLevelComponent[];
|
||||||
/**
|
/**
|
||||||
* Sent if the message contains stickers
|
* Sent if the message contains stickers
|
||||||
*
|
*
|
||||||
@ -813,6 +821,14 @@ export enum MessageFlags {
|
|||||||
* This message is a voice message
|
* This message is a voice message
|
||||||
*/
|
*/
|
||||||
IsVoiceMessage = 1 << 13,
|
IsVoiceMessage = 1 << 13,
|
||||||
|
/**
|
||||||
|
* This message has a snapshot (via Message Forwarding)
|
||||||
|
*/
|
||||||
|
HasSnapshot = 1 << 14,
|
||||||
|
/**
|
||||||
|
* This message allows you to create fully component driven messages
|
||||||
|
*/
|
||||||
|
IsComponentsV2 = 1 << 15,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1498,403 +1514,3 @@ export interface APIAllowedMentions {
|
|||||||
*/
|
*/
|
||||||
replied_user?: boolean;
|
replied_user?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#component-object
|
|
||||||
*/
|
|
||||||
export interface APIBaseComponent<T extends ComponentType> {
|
|
||||||
/**
|
|
||||||
* The type of the component
|
|
||||||
*/
|
|
||||||
type: T;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#component-object-component-types
|
|
||||||
*/
|
|
||||||
export enum ComponentType {
|
|
||||||
/**
|
|
||||||
* Action Row component
|
|
||||||
*/
|
|
||||||
ActionRow = 1,
|
|
||||||
/**
|
|
||||||
* Button component
|
|
||||||
*/
|
|
||||||
Button,
|
|
||||||
/**
|
|
||||||
* Select menu for picking from defined text options
|
|
||||||
*/
|
|
||||||
StringSelect,
|
|
||||||
/**
|
|
||||||
* Text Input component
|
|
||||||
*/
|
|
||||||
TextInput,
|
|
||||||
/**
|
|
||||||
* Select menu for users
|
|
||||||
*/
|
|
||||||
UserSelect,
|
|
||||||
/**
|
|
||||||
* Select menu for roles
|
|
||||||
*/
|
|
||||||
RoleSelect,
|
|
||||||
/**
|
|
||||||
* Select menu for users and roles
|
|
||||||
*/
|
|
||||||
MentionableSelect,
|
|
||||||
/**
|
|
||||||
* Select menu for channels
|
|
||||||
*/
|
|
||||||
ChannelSelect,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#action-rows
|
|
||||||
*/
|
|
||||||
export interface APIActionRowComponent<T extends APIActionRowComponentTypes>
|
|
||||||
extends APIBaseComponent<ComponentType.ActionRow> {
|
|
||||||
/**
|
|
||||||
* The components in the ActionRow
|
|
||||||
*/
|
|
||||||
components: T[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#buttons
|
|
||||||
*/
|
|
||||||
export interface APIButtonComponentBase<Style extends ButtonStyle> extends APIBaseComponent<ComponentType.Button> {
|
|
||||||
/**
|
|
||||||
* The label to be displayed on the button
|
|
||||||
*/
|
|
||||||
label?: string;
|
|
||||||
/**
|
|
||||||
* The style of the button
|
|
||||||
*/
|
|
||||||
style: Style;
|
|
||||||
/**
|
|
||||||
* The emoji to display to the left of the text
|
|
||||||
*/
|
|
||||||
emoji?: APIMessageComponentEmoji;
|
|
||||||
/**
|
|
||||||
* The status of the button
|
|
||||||
*/
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface APIMessageComponentEmoji {
|
|
||||||
/**
|
|
||||||
* Emoji id
|
|
||||||
*/
|
|
||||||
id?: Snowflake;
|
|
||||||
/**
|
|
||||||
* Emoji name
|
|
||||||
*/
|
|
||||||
name?: string;
|
|
||||||
/**
|
|
||||||
* Whether this emoji is animated
|
|
||||||
*/
|
|
||||||
animated?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface APIButtonComponentWithCustomId
|
|
||||||
extends APIButtonComponentBase<
|
|
||||||
ButtonStyle.Danger | ButtonStyle.Primary | ButtonStyle.Secondary | ButtonStyle.Success
|
|
||||||
> {
|
|
||||||
/**
|
|
||||||
* The custom_id to be sent in the interaction when clicked
|
|
||||||
*/
|
|
||||||
custom_id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface APIButtonComponentWithURL extends APIButtonComponentBase<ButtonStyle.Link> {
|
|
||||||
/**
|
|
||||||
* The URL to direct users to when clicked for Link buttons
|
|
||||||
*/
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface APIButtonComponentWithSKUId
|
|
||||||
extends Omit<APIButtonComponentBase<ButtonStyle.Premium>, 'custom_id' | 'emoji' | 'label'> {
|
|
||||||
/**
|
|
||||||
* The id for a purchasable SKU
|
|
||||||
*/
|
|
||||||
sku_id: Snowflake;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type APIButtonComponent =
|
|
||||||
| APIButtonComponentWithCustomId
|
|
||||||
| APIButtonComponentWithSKUId
|
|
||||||
| APIButtonComponentWithURL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#button-object-button-styles
|
|
||||||
*/
|
|
||||||
export enum ButtonStyle {
|
|
||||||
Primary = 1,
|
|
||||||
Secondary,
|
|
||||||
Success,
|
|
||||||
Danger,
|
|
||||||
Link,
|
|
||||||
Premium,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#text-inputs-text-input-styles
|
|
||||||
*/
|
|
||||||
export enum TextInputStyle {
|
|
||||||
Short = 1,
|
|
||||||
Paragraph,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
|
||||||
*/
|
|
||||||
export interface APIBaseSelectMenuComponent<
|
|
||||||
T extends
|
|
||||||
| ComponentType.ChannelSelect
|
|
||||||
| ComponentType.MentionableSelect
|
|
||||||
| ComponentType.RoleSelect
|
|
||||||
| ComponentType.StringSelect
|
|
||||||
| ComponentType.UserSelect,
|
|
||||||
> extends APIBaseComponent<T> {
|
|
||||||
/**
|
|
||||||
* A developer-defined identifier for the select menu, max 100 characters
|
|
||||||
*/
|
|
||||||
custom_id: string;
|
|
||||||
/**
|
|
||||||
* Custom placeholder text if nothing is selected, max 150 characters
|
|
||||||
*/
|
|
||||||
placeholder?: string;
|
|
||||||
/**
|
|
||||||
* The minimum number of items that must be chosen; min 0, max 25
|
|
||||||
*
|
|
||||||
* @default 1
|
|
||||||
*/
|
|
||||||
min_values?: number;
|
|
||||||
/**
|
|
||||||
* The maximum number of items that can be chosen; max 25
|
|
||||||
*
|
|
||||||
* @default 1
|
|
||||||
*/
|
|
||||||
max_values?: number;
|
|
||||||
/**
|
|
||||||
* Disable the select
|
|
||||||
*
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface APIBaseAutoPopulatedSelectMenuComponent<
|
|
||||||
T extends
|
|
||||||
| ComponentType.ChannelSelect
|
|
||||||
| ComponentType.MentionableSelect
|
|
||||||
| ComponentType.RoleSelect
|
|
||||||
| ComponentType.UserSelect,
|
|
||||||
D extends SelectMenuDefaultValueType,
|
|
||||||
> extends APIBaseSelectMenuComponent<T> {
|
|
||||||
/**
|
|
||||||
* List of default values for auto-populated select menu components
|
|
||||||
*/
|
|
||||||
default_values?: APISelectMenuDefaultValue<D>[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
|
||||||
*/
|
|
||||||
export interface APIStringSelectComponent extends APIBaseSelectMenuComponent<ComponentType.StringSelect> {
|
|
||||||
/**
|
|
||||||
* Specified choices in a select menu; max 25
|
|
||||||
*/
|
|
||||||
options: APISelectMenuOption[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
|
||||||
*/
|
|
||||||
export type APIUserSelectComponent = APIBaseAutoPopulatedSelectMenuComponent<
|
|
||||||
ComponentType.UserSelect,
|
|
||||||
SelectMenuDefaultValueType.User
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
|
||||||
*/
|
|
||||||
export type APIRoleSelectComponent = APIBaseAutoPopulatedSelectMenuComponent<
|
|
||||||
ComponentType.RoleSelect,
|
|
||||||
SelectMenuDefaultValueType.Role
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
|
||||||
*/
|
|
||||||
export type APIMentionableSelectComponent = APIBaseAutoPopulatedSelectMenuComponent<
|
|
||||||
ComponentType.MentionableSelect,
|
|
||||||
SelectMenuDefaultValueType.Role | SelectMenuDefaultValueType.User
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
|
||||||
*/
|
|
||||||
export interface APIChannelSelectComponent
|
|
||||||
extends APIBaseAutoPopulatedSelectMenuComponent<ComponentType.ChannelSelect, SelectMenuDefaultValueType.Channel> {
|
|
||||||
/**
|
|
||||||
* List of channel types to include in the ChannelSelect component
|
|
||||||
*/
|
|
||||||
channel_types?: ChannelType[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-default-value-structure
|
|
||||||
*/
|
|
||||||
export enum SelectMenuDefaultValueType {
|
|
||||||
Channel = 'channel',
|
|
||||||
Role = 'role',
|
|
||||||
User = 'user',
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-default-value-structure
|
|
||||||
*/
|
|
||||||
export interface APISelectMenuDefaultValue<T extends SelectMenuDefaultValueType> {
|
|
||||||
type: T;
|
|
||||||
id: Snowflake;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type APIAutoPopulatedSelectMenuComponent =
|
|
||||||
| APIChannelSelectComponent
|
|
||||||
| APIMentionableSelectComponent
|
|
||||||
| APIRoleSelectComponent
|
|
||||||
| APIUserSelectComponent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
|
||||||
*/
|
|
||||||
export type APISelectMenuComponent =
|
|
||||||
| APIChannelSelectComponent
|
|
||||||
| APIMentionableSelectComponent
|
|
||||||
| APIRoleSelectComponent
|
|
||||||
| APIStringSelectComponent
|
|
||||||
| APIUserSelectComponent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-option-structure
|
|
||||||
*/
|
|
||||||
export interface APISelectMenuOption {
|
|
||||||
/**
|
|
||||||
* The user-facing name of the option (max 100 chars)
|
|
||||||
*/
|
|
||||||
label: string;
|
|
||||||
/**
|
|
||||||
* The dev-defined value of the option (max 100 chars)
|
|
||||||
*/
|
|
||||||
value: string;
|
|
||||||
/**
|
|
||||||
* An additional description of the option (max 100 chars)
|
|
||||||
*/
|
|
||||||
description?: string;
|
|
||||||
/**
|
|
||||||
* The emoji to display to the left of the option
|
|
||||||
*/
|
|
||||||
emoji?: APIMessageComponentEmoji;
|
|
||||||
/**
|
|
||||||
* Whether this option should be already-selected by default
|
|
||||||
*/
|
|
||||||
default?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#text-inputs-text-input-structure
|
|
||||||
*/
|
|
||||||
export interface APITextInputComponent extends APIBaseComponent<ComponentType.TextInput> {
|
|
||||||
/**
|
|
||||||
* One of text input styles
|
|
||||||
*/
|
|
||||||
style: TextInputStyle;
|
|
||||||
/**
|
|
||||||
* The custom id for the text input
|
|
||||||
*/
|
|
||||||
custom_id: string;
|
|
||||||
/**
|
|
||||||
* Text that appears on top of the text input field, max 45 characters
|
|
||||||
*/
|
|
||||||
label: string;
|
|
||||||
/**
|
|
||||||
* Placeholder for the text input
|
|
||||||
*/
|
|
||||||
placeholder?: string;
|
|
||||||
/**
|
|
||||||
* The pre-filled text in the text input
|
|
||||||
*/
|
|
||||||
value?: string;
|
|
||||||
/**
|
|
||||||
* Minimal length of text input
|
|
||||||
*/
|
|
||||||
min_length?: number;
|
|
||||||
/**
|
|
||||||
* Maximal length of text input
|
|
||||||
*/
|
|
||||||
max_length?: number;
|
|
||||||
/**
|
|
||||||
* Whether or not this text input is required or not
|
|
||||||
*/
|
|
||||||
required?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/resources/channel#channel-object-channel-flags
|
|
||||||
*/
|
|
||||||
export enum ChannelFlags {
|
|
||||||
/**
|
|
||||||
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
|
||||||
*/
|
|
||||||
GuildFeedRemoved = 1 << 0,
|
|
||||||
/**
|
|
||||||
* This thread is pinned to the top of its parent forum channel
|
|
||||||
*/
|
|
||||||
Pinned = 1 << 1,
|
|
||||||
/**
|
|
||||||
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
|
||||||
*/
|
|
||||||
ActiveChannelsRemoved = 1 << 2,
|
|
||||||
/**
|
|
||||||
* Whether a tag is required to be specified when creating a thread in a forum channel.
|
|
||||||
* Tags are specified in the `applied_tags` field
|
|
||||||
*/
|
|
||||||
RequireTag = 1 << 4,
|
|
||||||
/**
|
|
||||||
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
|
||||||
*/
|
|
||||||
IsSpam = 1 << 5,
|
|
||||||
/**
|
|
||||||
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
|
||||||
*/
|
|
||||||
IsGuildResourceChannel = 1 << 7,
|
|
||||||
/**
|
|
||||||
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
|
||||||
*/
|
|
||||||
ClydeAI = 1 << 8,
|
|
||||||
/**
|
|
||||||
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
|
||||||
*/
|
|
||||||
IsScheduledForDeletion = 1 << 9,
|
|
||||||
/**
|
|
||||||
* Whether media download options are hidden.
|
|
||||||
*/
|
|
||||||
HideMediaDownloadOptions = 1 << 15,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#message-components
|
|
||||||
*/
|
|
||||||
export type APIMessageComponent = APIActionRowComponent<APIMessageActionRowComponent> | APIMessageActionRowComponent;
|
|
||||||
export type APIModalComponent = APIActionRowComponent<APIModalActionRowComponent> | APIModalActionRowComponent;
|
|
||||||
|
|
||||||
export type APIActionRowComponentTypes = APIMessageActionRowComponent | APIModalActionRowComponent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#message-components
|
|
||||||
*/
|
|
||||||
export type APIMessageActionRowComponent = APIButtonComponent | APISelectMenuComponent;
|
|
||||||
|
|
||||||
// Modal components
|
|
||||||
export type APIModalActionRowComponent = APITextInputComponent;
|
|
||||||
|
594
src/types/payloads/components.ts
Normal file
594
src/types/payloads/components.ts
Normal file
@ -0,0 +1,594 @@
|
|||||||
|
import type { APIAttachment, Snowflake } from '..';
|
||||||
|
import type { Identify, MakeRequired } from '../../common';
|
||||||
|
import type { ChannelType } from '../utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#component-object
|
||||||
|
*/
|
||||||
|
export interface APIBaseComponent<T extends ComponentType> {
|
||||||
|
/**
|
||||||
|
* The type of the component
|
||||||
|
*/
|
||||||
|
type: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#component-object-component-types
|
||||||
|
*/
|
||||||
|
export enum ComponentType {
|
||||||
|
/**
|
||||||
|
* Action Row component
|
||||||
|
*/
|
||||||
|
ActionRow = 1,
|
||||||
|
/**
|
||||||
|
* Button component
|
||||||
|
*/
|
||||||
|
Button,
|
||||||
|
/**
|
||||||
|
* Select menu for picking from defined text options
|
||||||
|
*/
|
||||||
|
StringSelect,
|
||||||
|
/**
|
||||||
|
* Text Input component
|
||||||
|
*/
|
||||||
|
TextInput,
|
||||||
|
/**
|
||||||
|
* Select menu for users
|
||||||
|
*/
|
||||||
|
UserSelect,
|
||||||
|
/**
|
||||||
|
* Select menu for roles
|
||||||
|
*/
|
||||||
|
RoleSelect,
|
||||||
|
/**
|
||||||
|
* Select menu for users and roles
|
||||||
|
*/
|
||||||
|
MentionableSelect,
|
||||||
|
/**
|
||||||
|
* Select menu for channels
|
||||||
|
*/
|
||||||
|
ChannelSelect,
|
||||||
|
/**
|
||||||
|
* Section for accessory
|
||||||
|
*/
|
||||||
|
Section,
|
||||||
|
/**
|
||||||
|
* Text display component
|
||||||
|
*/
|
||||||
|
TextDisplay,
|
||||||
|
/**
|
||||||
|
* Thumbnail component
|
||||||
|
*/
|
||||||
|
Thumbnail,
|
||||||
|
/**
|
||||||
|
* Media Gallery component
|
||||||
|
*/
|
||||||
|
MediaGallery,
|
||||||
|
/**
|
||||||
|
* File component
|
||||||
|
*/
|
||||||
|
File,
|
||||||
|
/**
|
||||||
|
* Separator component
|
||||||
|
*/
|
||||||
|
Separator,
|
||||||
|
/**
|
||||||
|
* Container component
|
||||||
|
*/
|
||||||
|
Container = 17,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#action-rows
|
||||||
|
*/
|
||||||
|
export interface APIActionRowComponent<T extends APIActionRowComponentTypes>
|
||||||
|
extends APIBaseComponent<ComponentType.ActionRow> {
|
||||||
|
/**
|
||||||
|
* The components in the ActionRow
|
||||||
|
*/
|
||||||
|
components: T[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#buttons
|
||||||
|
*/
|
||||||
|
export interface APIButtonComponentBase<Style extends ButtonStyle> extends APIBaseComponent<ComponentType.Button> {
|
||||||
|
/**
|
||||||
|
* The label to be displayed on the button
|
||||||
|
*/
|
||||||
|
label?: string;
|
||||||
|
/**
|
||||||
|
* The style of the button
|
||||||
|
*/
|
||||||
|
style: Style;
|
||||||
|
/**
|
||||||
|
* The emoji to display to the left of the text
|
||||||
|
*/
|
||||||
|
emoji?: APIMessageComponentEmoji;
|
||||||
|
/**
|
||||||
|
* The status of the button
|
||||||
|
*/
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface APIMessageComponentEmoji {
|
||||||
|
/**
|
||||||
|
* Emoji id
|
||||||
|
*/
|
||||||
|
id?: Snowflake;
|
||||||
|
/**
|
||||||
|
* Emoji name
|
||||||
|
*/
|
||||||
|
name?: string;
|
||||||
|
/**
|
||||||
|
* Whether this emoji is animated
|
||||||
|
*/
|
||||||
|
animated?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface APIButtonComponentWithCustomId
|
||||||
|
extends APIButtonComponentBase<
|
||||||
|
ButtonStyle.Danger | ButtonStyle.Primary | ButtonStyle.Secondary | ButtonStyle.Success
|
||||||
|
> {
|
||||||
|
/**
|
||||||
|
* The custom_id to be sent in the interaction when clicked
|
||||||
|
*/
|
||||||
|
custom_id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface APIButtonComponentWithURL extends APIButtonComponentBase<ButtonStyle.Link> {
|
||||||
|
/**
|
||||||
|
* The URL to direct users to when clicked for Link buttons
|
||||||
|
*/
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface APIButtonComponentWithSKUId
|
||||||
|
extends Omit<APIButtonComponentBase<ButtonStyle.Premium>, 'custom_id' | 'emoji' | 'label'> {
|
||||||
|
/**
|
||||||
|
* The id for a purchasable SKU
|
||||||
|
*/
|
||||||
|
sku_id: Snowflake;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type APIButtonComponent =
|
||||||
|
| APIButtonComponentWithCustomId
|
||||||
|
| APIButtonComponentWithSKUId
|
||||||
|
| APIButtonComponentWithURL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#button-object-button-styles
|
||||||
|
*/
|
||||||
|
export enum ButtonStyle {
|
||||||
|
Primary = 1,
|
||||||
|
Secondary,
|
||||||
|
Success,
|
||||||
|
Danger,
|
||||||
|
Link,
|
||||||
|
Premium,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#text-inputs-text-input-styles
|
||||||
|
*/
|
||||||
|
export enum TextInputStyle {
|
||||||
|
Short = 1,
|
||||||
|
Paragraph,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||||
|
*/
|
||||||
|
export interface APIBaseSelectMenuComponent<
|
||||||
|
T extends
|
||||||
|
| ComponentType.ChannelSelect
|
||||||
|
| ComponentType.MentionableSelect
|
||||||
|
| ComponentType.RoleSelect
|
||||||
|
| ComponentType.StringSelect
|
||||||
|
| ComponentType.UserSelect,
|
||||||
|
> extends APIBaseComponent<T> {
|
||||||
|
/**
|
||||||
|
* A developer-defined identifier for the select menu, max 100 characters
|
||||||
|
*/
|
||||||
|
custom_id: string;
|
||||||
|
/**
|
||||||
|
* Custom placeholder text if nothing is selected, max 150 characters
|
||||||
|
*/
|
||||||
|
placeholder?: string;
|
||||||
|
/**
|
||||||
|
* The minimum number of items that must be chosen; min 0, max 25
|
||||||
|
*
|
||||||
|
* @default 1
|
||||||
|
*/
|
||||||
|
min_values?: number;
|
||||||
|
/**
|
||||||
|
* The maximum number of items that can be chosen; max 25
|
||||||
|
*
|
||||||
|
* @default 1
|
||||||
|
*/
|
||||||
|
max_values?: number;
|
||||||
|
/**
|
||||||
|
* Disable the select
|
||||||
|
*
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface APIBaseAutoPopulatedSelectMenuComponent<
|
||||||
|
T extends
|
||||||
|
| ComponentType.ChannelSelect
|
||||||
|
| ComponentType.MentionableSelect
|
||||||
|
| ComponentType.RoleSelect
|
||||||
|
| ComponentType.UserSelect,
|
||||||
|
D extends SelectMenuDefaultValueType,
|
||||||
|
> extends APIBaseSelectMenuComponent<T> {
|
||||||
|
/**
|
||||||
|
* List of default values for auto-populated select menu components
|
||||||
|
*/
|
||||||
|
default_values?: APISelectMenuDefaultValue<D>[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||||
|
*/
|
||||||
|
export interface APIStringSelectComponent extends APIBaseSelectMenuComponent<ComponentType.StringSelect> {
|
||||||
|
/**
|
||||||
|
* Specified choices in a select menu; max 25
|
||||||
|
*/
|
||||||
|
options: APISelectMenuOption[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||||
|
*/
|
||||||
|
export type APIUserSelectComponent = APIBaseAutoPopulatedSelectMenuComponent<
|
||||||
|
ComponentType.UserSelect,
|
||||||
|
SelectMenuDefaultValueType.User
|
||||||
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||||
|
*/
|
||||||
|
export type APIRoleSelectComponent = APIBaseAutoPopulatedSelectMenuComponent<
|
||||||
|
ComponentType.RoleSelect,
|
||||||
|
SelectMenuDefaultValueType.Role
|
||||||
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||||
|
*/
|
||||||
|
export type APIMentionableSelectComponent = APIBaseAutoPopulatedSelectMenuComponent<
|
||||||
|
ComponentType.MentionableSelect,
|
||||||
|
SelectMenuDefaultValueType.Role | SelectMenuDefaultValueType.User
|
||||||
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||||
|
*/
|
||||||
|
export interface APIChannelSelectComponent
|
||||||
|
extends APIBaseAutoPopulatedSelectMenuComponent<ComponentType.ChannelSelect, SelectMenuDefaultValueType.Channel> {
|
||||||
|
/**
|
||||||
|
* List of channel types to include in the ChannelSelect component
|
||||||
|
*/
|
||||||
|
channel_types?: ChannelType[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-default-value-structure
|
||||||
|
*/
|
||||||
|
export enum SelectMenuDefaultValueType {
|
||||||
|
Channel = 'channel',
|
||||||
|
Role = 'role',
|
||||||
|
User = 'user',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-default-value-structure
|
||||||
|
*/
|
||||||
|
export interface APISelectMenuDefaultValue<T extends SelectMenuDefaultValueType> {
|
||||||
|
type: T;
|
||||||
|
id: Snowflake;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type APIAutoPopulatedSelectMenuComponent =
|
||||||
|
| APIChannelSelectComponent
|
||||||
|
| APIMentionableSelectComponent
|
||||||
|
| APIRoleSelectComponent
|
||||||
|
| APIUserSelectComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||||
|
*/
|
||||||
|
export type APISelectMenuComponent =
|
||||||
|
| APIChannelSelectComponent
|
||||||
|
| APIMentionableSelectComponent
|
||||||
|
| APIRoleSelectComponent
|
||||||
|
| APIStringSelectComponent
|
||||||
|
| APIUserSelectComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-option-structure
|
||||||
|
*/
|
||||||
|
export interface APISelectMenuOption {
|
||||||
|
/**
|
||||||
|
* The user-facing name of the option (max 100 chars)
|
||||||
|
*/
|
||||||
|
label: string;
|
||||||
|
/**
|
||||||
|
* The dev-defined value of the option (max 100 chars)
|
||||||
|
*/
|
||||||
|
value: string;
|
||||||
|
/**
|
||||||
|
* An additional description of the option (max 100 chars)
|
||||||
|
*/
|
||||||
|
description?: string;
|
||||||
|
/**
|
||||||
|
* The emoji to display to the left of the option
|
||||||
|
*/
|
||||||
|
emoji?: APIMessageComponentEmoji;
|
||||||
|
/**
|
||||||
|
* Whether this option should be already-selected by default
|
||||||
|
*/
|
||||||
|
default?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#text-inputs-text-input-structure
|
||||||
|
*/
|
||||||
|
export interface APITextInputComponent extends APIBaseComponent<ComponentType.TextInput> {
|
||||||
|
/**
|
||||||
|
* One of text input styles
|
||||||
|
*/
|
||||||
|
style: TextInputStyle;
|
||||||
|
/**
|
||||||
|
* The custom id for the text input
|
||||||
|
*/
|
||||||
|
custom_id: string;
|
||||||
|
/**
|
||||||
|
* Text that appears on top of the text input field, max 45 characters
|
||||||
|
*/
|
||||||
|
label: string;
|
||||||
|
/**
|
||||||
|
* Placeholder for the text input
|
||||||
|
*/
|
||||||
|
placeholder?: string;
|
||||||
|
/**
|
||||||
|
* The pre-filled text in the text input
|
||||||
|
*/
|
||||||
|
value?: string;
|
||||||
|
/**
|
||||||
|
* Minimal length of text input
|
||||||
|
*/
|
||||||
|
min_length?: number;
|
||||||
|
/**
|
||||||
|
* Maximal length of text input
|
||||||
|
*/
|
||||||
|
max_length?: number;
|
||||||
|
/**
|
||||||
|
* Whether or not this text input is required or not
|
||||||
|
*/
|
||||||
|
required?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/resources/channel#channel-object-channel-flags
|
||||||
|
*/
|
||||||
|
export enum ChannelFlags {
|
||||||
|
/**
|
||||||
|
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
||||||
|
*/
|
||||||
|
GuildFeedRemoved = 1 << 0,
|
||||||
|
/**
|
||||||
|
* This thread is pinned to the top of its parent forum channel
|
||||||
|
*/
|
||||||
|
Pinned = 1 << 1,
|
||||||
|
/**
|
||||||
|
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
||||||
|
*/
|
||||||
|
ActiveChannelsRemoved = 1 << 2,
|
||||||
|
/**
|
||||||
|
* Whether a tag is required to be specified when creating a thread in a forum channel.
|
||||||
|
* Tags are specified in the `applied_tags` field
|
||||||
|
*/
|
||||||
|
RequireTag = 1 << 4,
|
||||||
|
/**
|
||||||
|
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
||||||
|
*/
|
||||||
|
IsSpam = 1 << 5,
|
||||||
|
/**
|
||||||
|
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
||||||
|
*/
|
||||||
|
IsGuildResourceChannel = 1 << 7,
|
||||||
|
/**
|
||||||
|
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
||||||
|
*/
|
||||||
|
ClydeAI = 1 << 8,
|
||||||
|
/**
|
||||||
|
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
||||||
|
*/
|
||||||
|
IsScheduledForDeletion = 1 << 9,
|
||||||
|
/**
|
||||||
|
* Whether media download options are hidden.
|
||||||
|
*/
|
||||||
|
HideMediaDownloadOptions = 1 << 15,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#message-components
|
||||||
|
*/
|
||||||
|
export type APIMessageComponent = APIActionRowComponent<APIMessageActionRowComponent> | APIMessageActionRowComponent;
|
||||||
|
export type APIModalComponent = APIActionRowComponent<APIModalActionRowComponent> | APIModalActionRowComponent;
|
||||||
|
|
||||||
|
export type APIActionRowComponentTypes = APIMessageActionRowComponent | APIModalActionRowComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#message-components
|
||||||
|
*/
|
||||||
|
export type APIMessageActionRowComponent = APIButtonComponent | APISelectMenuComponent;
|
||||||
|
|
||||||
|
export type APIComponents =
|
||||||
|
| APIMessageActionRowComponent
|
||||||
|
| APIModalActionRowComponent
|
||||||
|
| APIContainerComponent
|
||||||
|
| APIContainerComponents
|
||||||
|
| APITopLevelComponent;
|
||||||
|
|
||||||
|
// Modal components
|
||||||
|
export type APIModalActionRowComponent = APITextInputComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#section
|
||||||
|
*
|
||||||
|
* A Section is a top-level layout component that allows you to join text contextually with an accessory.
|
||||||
|
*/
|
||||||
|
export interface APISectionComponent {
|
||||||
|
/** 9 for section component */
|
||||||
|
type: ComponentType.Section;
|
||||||
|
/** Optional identifier for component */
|
||||||
|
id?: number;
|
||||||
|
/** One to three text components */
|
||||||
|
components: APITextDispalyComponent[];
|
||||||
|
/** A thumbnail or a button component, with a future possibility of adding more compatible components */
|
||||||
|
accessory: APIButtonComponent | APIThumbnailComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#text-display
|
||||||
|
*
|
||||||
|
* A Text Display is a top-level content component that allows you to add text to your message formatted with markdown and mention users and roles. This is similar to the content field of a message, but allows you to add multiple text components, controlling the layout of your message.
|
||||||
|
* Text Displays are only available in messages.
|
||||||
|
*/
|
||||||
|
export interface APITextDispalyComponent {
|
||||||
|
/** 10 for text display */
|
||||||
|
type: ComponentType.TextDisplay;
|
||||||
|
/** Optional identifier for component */
|
||||||
|
id?: number;
|
||||||
|
/** Text that will be displayed similar to a message */
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#thumbnail
|
||||||
|
*
|
||||||
|
* A Thumbnail is a content component that is a small image only usable as an accessory in a section. The preview comes from an url or attachment through the unfurled media item structure.
|
||||||
|
* Thumbnails are only available in messages as an accessory in a section.
|
||||||
|
*/
|
||||||
|
export interface APIThumbnailComponent {
|
||||||
|
/** 11 for thumbnail */
|
||||||
|
type: ComponentType.Thumbnail;
|
||||||
|
/** Optional identifier for component */
|
||||||
|
id?: number;
|
||||||
|
/** A url or attachment */
|
||||||
|
media: APIUnfurledMediaItem;
|
||||||
|
/** Alt text for the media */
|
||||||
|
description?: string;
|
||||||
|
/** Whether the thumbnail should be a spoiler (or blurred out). Defaults to false */
|
||||||
|
spoiler?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#media-gallery
|
||||||
|
*
|
||||||
|
* A Media Gallery is a top-level content component that allows you to display 1-10 media attachments in an organized gallery format. Each item can have optional descriptions and can be marked as spoilers.
|
||||||
|
* Media Galleries are only available in messages.
|
||||||
|
*/
|
||||||
|
export interface APIMediaGalleryComponent {
|
||||||
|
/** 12 for media gallery */
|
||||||
|
type: ComponentType.MediaGallery;
|
||||||
|
/** Optional identifier for component */
|
||||||
|
id?: number;
|
||||||
|
/** 1 to 10 media gallery items */
|
||||||
|
items: APIMediaGalleryItems[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface APIMediaGalleryItems {
|
||||||
|
/** A url or attachment */
|
||||||
|
media: APIUnfurledMediaItem;
|
||||||
|
/** Alt text for the media */
|
||||||
|
description?: string;
|
||||||
|
/** Whether the thumbnail should be a spoiler (or blurred out). Defaults to false */
|
||||||
|
spoiler?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#file
|
||||||
|
*
|
||||||
|
* A File is a top-level component that allows you to display an uploaded file as an attachment to the message and reference it in the component. Each file component can only display 1 attached file, but you can upload multiple files and add them to different file components within your payload. This is similar to the embeds field of a message but allows you to control the layout of your message by using this anywhere as a component.
|
||||||
|
* Files are only available in messages.
|
||||||
|
*/
|
||||||
|
export interface APIFileComponent {
|
||||||
|
/** 13 for file */
|
||||||
|
type: ComponentType.File;
|
||||||
|
/** Optional identifier for component */
|
||||||
|
id?: number;
|
||||||
|
/** This unfurled media item is unique in that it only supports attachment references using the attachment://<filename> syntax */
|
||||||
|
file: APIUnfurledMediaItem;
|
||||||
|
/** Whether the media should be a spoiler (or blurred out). Defaults to false */
|
||||||
|
spoiler?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#separator
|
||||||
|
*
|
||||||
|
* A Separator is a top-level layout component that adds vertical padding and visual division between other components.
|
||||||
|
*/
|
||||||
|
export interface APISeparatorComponent {
|
||||||
|
/** 14 for separator */
|
||||||
|
type: ComponentType.Separator;
|
||||||
|
/** Optional identifier for component */
|
||||||
|
id?: number;
|
||||||
|
/** Whether a visual divider should be displayed in the component. Defaults to true */
|
||||||
|
divider?: boolean;
|
||||||
|
/** Size of separator padding—1 for small padding, 2 for large padding. Defaults to 1 */
|
||||||
|
spacing?: Spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Spacing {
|
||||||
|
/** For small padding */
|
||||||
|
Small = 1,
|
||||||
|
/** For large padding */
|
||||||
|
Large,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type APIContainerComponents =
|
||||||
|
| APIActionRowComponent<APIActionRowComponentTypes>
|
||||||
|
| APITextDispalyComponent
|
||||||
|
| APISectionComponent
|
||||||
|
| APIMediaGalleryComponent
|
||||||
|
| APIFileComponent
|
||||||
|
| APISeparatorComponent
|
||||||
|
| APIThumbnailComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#container
|
||||||
|
*/
|
||||||
|
export interface APIContainerComponent {
|
||||||
|
/** 15 for container */
|
||||||
|
type: ComponentType.Container;
|
||||||
|
/** Optional identifier for component */
|
||||||
|
id?: number;
|
||||||
|
/** Up to 10 components of the type action row, text display, section, media gallery, separator, or file */
|
||||||
|
components: APIContainerComponents[];
|
||||||
|
/** Color for the accent on the container as RGB from 0x000000 to 0xFFFFFF */
|
||||||
|
accent_color?: number;
|
||||||
|
/** Whether the container should be a spoiler (or blurred out). Defaults to false. */
|
||||||
|
spoiler?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#unfurled-media-item-structure
|
||||||
|
*/
|
||||||
|
export interface APIUnfurledMediaItem
|
||||||
|
extends Identify<
|
||||||
|
MakeRequired<Partial<Pick<APIAttachment, 'url' | 'proxy_url' | 'height' | 'width' | 'content_type'>>, 'url'>
|
||||||
|
> {}
|
||||||
|
|
||||||
|
export type APITopLevelComponent =
|
||||||
|
| APIContainerComponent
|
||||||
|
| APIActionRowComponent<APIActionRowComponentTypes>
|
||||||
|
| APIFileComponent
|
||||||
|
| APIMediaGalleryComponent
|
||||||
|
| APISectionComponent
|
||||||
|
| APISeparatorComponent
|
||||||
|
| APITextDispalyComponent;
|
@ -20,6 +20,7 @@ export * from './voice';
|
|||||||
export * from './webhook';
|
export * from './webhook';
|
||||||
export * from './monetization';
|
export * from './monetization';
|
||||||
export * from './soundboard';
|
export * from './soundboard';
|
||||||
|
export * from './components';
|
||||||
|
|
||||||
import type { LocaleString } from '../rest';
|
import type { LocaleString } from '../rest';
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import type { ChannelType, OverwriteType, Permissions, Snowflake, VideoQualityMode } from '..';
|
import type { ChannelType, OverwriteType, Permissions, Snowflake, VideoQualityMode } from '..';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
APIActionRowComponent,
|
|
||||||
APIAllowedMentions,
|
APIAllowedMentions,
|
||||||
APIAttachment,
|
APIAttachment,
|
||||||
APIChannel,
|
APIChannel,
|
||||||
@ -11,10 +10,10 @@ import type {
|
|||||||
APIGuildForumDefaultReactionEmoji,
|
APIGuildForumDefaultReactionEmoji,
|
||||||
APIGuildForumTag,
|
APIGuildForumTag,
|
||||||
APIMessage,
|
APIMessage,
|
||||||
APIMessageActionRowComponent,
|
|
||||||
APIMessageReference,
|
APIMessageReference,
|
||||||
APIThreadList,
|
APIThreadList,
|
||||||
APIThreadMember,
|
APIThreadMember,
|
||||||
|
APITopLevelComponent,
|
||||||
APIUser,
|
APIUser,
|
||||||
ChannelFlags,
|
ChannelFlags,
|
||||||
ForumLayoutType,
|
ForumLayoutType,
|
||||||
@ -294,7 +293,7 @@ export interface RESTPostAPIChannelMessageJSONBody {
|
|||||||
*
|
*
|
||||||
* See https://discord.com/developers/docs/interactions/message-components#component-object
|
* See https://discord.com/developers/docs/interactions/message-components#component-object
|
||||||
*/
|
*/
|
||||||
components?: APIActionRowComponent<APIMessageActionRowComponent>[] | undefined;
|
components?: APITopLevelComponent[] | undefined;
|
||||||
/**
|
/**
|
||||||
* IDs of up to 3 stickers in the server to send in the message
|
* IDs of up to 3 stickers in the server to send in the message
|
||||||
*
|
*
|
||||||
@ -442,7 +441,7 @@ export interface RESTPatchAPIChannelMessageJSONBody {
|
|||||||
*
|
*
|
||||||
* See https://discord.com/developers/docs/interactions/message-components#component-object
|
* See https://discord.com/developers/docs/interactions/message-components#component-object
|
||||||
*/
|
*/
|
||||||
components?: APIActionRowComponent<APIMessageActionRowComponent>[] | null | undefined;
|
components?: APITopLevelComponent[] | null | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import type { Snowflake } from '..';
|
import type { Snowflake } from '..';
|
||||||
import type {
|
import type {
|
||||||
APIActionRowComponent,
|
|
||||||
APIAllowedMentions,
|
APIAllowedMentions,
|
||||||
APIEmbed,
|
APIEmbed,
|
||||||
APIMessage,
|
APIMessage,
|
||||||
APIMessageActionRowComponent,
|
APITopLevelComponent,
|
||||||
APIWebhook,
|
APIWebhook,
|
||||||
MessageFlags,
|
MessageFlags,
|
||||||
} from '../payloads';
|
} from '../payloads';
|
||||||
@ -136,7 +135,7 @@ export interface RESTPostAPIWebhookWithTokenJSONBody {
|
|||||||
*
|
*
|
||||||
* See https://discord.com/developers/docs/interactions/message-components#component-object
|
* See https://discord.com/developers/docs/interactions/message-components#component-object
|
||||||
*/
|
*/
|
||||||
components?: APIActionRowComponent<APIMessageActionRowComponent>[] | undefined;
|
components?: APITopLevelComponent[] | undefined;
|
||||||
/**
|
/**
|
||||||
* Attachment objects with filename and description
|
* Attachment objects with filename and description
|
||||||
*/
|
*/
|
||||||
@ -190,6 +189,14 @@ export interface RESTPostAPIWebhookWithTokenQuery {
|
|||||||
* Available only if the {@link RESTPostAPIWebhookWithTokenJSONBody.thread_name} JSON body property is not specified
|
* Available only if the {@link RESTPostAPIWebhookWithTokenJSONBody.thread_name} JSON body property is not specified
|
||||||
*/
|
*/
|
||||||
thread_id?: Snowflake;
|
thread_id?: Snowflake;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to respect the components field of the request. When enabled, allows application-owned webhooks to use all components and
|
||||||
|
* non-owned webhooks to use non-interactive components.
|
||||||
|
*
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
with_components?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -208,7 +215,7 @@ export type RESTPostAPIWebhookWithTokenWaitResult = APIMessage;
|
|||||||
/**
|
/**
|
||||||
* https://discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook-query-string-params
|
* https://discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook-query-string-params
|
||||||
*/
|
*/
|
||||||
export type RESTPostAPIWebhookWithTokenSlackQuery = RESTPostAPIWebhookWithTokenQuery;
|
export type RESTPostAPIWebhookWithTokenSlackQuery = Omit<RESTPostAPIWebhookWithTokenQuery, 'with_components'>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook
|
* https://discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook
|
||||||
@ -226,7 +233,7 @@ export type RESTPostAPIWebhookWithTokenSlackWaitResult = APIMessage;
|
|||||||
/**
|
/**
|
||||||
* https://discord.com/developers/docs/resources/webhook#execute-githubcompatible-webhook-query-string-params
|
* https://discord.com/developers/docs/resources/webhook#execute-githubcompatible-webhook-query-string-params
|
||||||
*/
|
*/
|
||||||
export type RESTPostAPIWebhookWithTokenGitHubQuery = RESTPostAPIWebhookWithTokenQuery;
|
export type RESTPostAPIWebhookWithTokenGitHubQuery = Omit<RESTPostAPIWebhookWithTokenQuery, 'with_components'>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://discord.com/developers/docs/resources/webhook#execute-githubcompatible-webhook
|
* https://discord.com/developers/docs/resources/webhook#execute-githubcompatible-webhook
|
||||||
@ -269,6 +276,7 @@ export type RESTPatchAPIWebhookWithTokenMessageJSONBody = AddUndefinedToPossibly
|
|||||||
attachments?: RESTAPIAttachment[] | undefined;
|
attachments?: RESTAPIAttachment[] | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type RESTPatchAPIWebhookWithTokenMessageQuery = Omit<RESTPostAPIWebhookWithTokenQuery, 'wait'>;
|
||||||
/**
|
/**
|
||||||
* https://discord.com/developers/docs/resources/webhook#edit-webhook-message
|
* https://discord.com/developers/docs/resources/webhook#edit-webhook-message
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user