Skip to content

Commit

Permalink
0.16.2 (#30)
Browse files Browse the repository at this point in the history
* Add `run` to both the component button and select menu helper

- Add `run` to both the component button and select menu helper
-> Allows you to listen for a button press directly on the button helper itself
-> Only listens for about 10 minutes (might change to customizable times in the future)

- Fix `Structures.Message.deleted` not updating on channel/guild deletes

- Update `Structures.Message`
-> Add `.hasFlagEphemeral`

- Update `Interactions.InteractionCommand`
-> Default `global` to false if `global` isn't present and `guildIds` is present

* Fix Component Helper's Typings

* Update `Structures.Message`

- Update `Structures.Message`
-> Add `.canEdit`
-> Add checks for ephemeral in `.canDelete`
-> Default `.deleted` as true if is an ephemeral message

* Add `Components`, Update `ShardClient`

- Add `Components` to `Utils`
-> Allows you to manage a message's components much easier as well as have a custom timeout and a listener to any button press on the message
--> Timeout is defaulted to 10 minutes

- Fix interaction commands not updating if a select menu option changes `required`

- Update `Structures.Member`
-> Add `.canEditRole()` (checks our role hierarchy with the role provided to see if its under us)

* Update `Constants`

- Update `Constants`
-> Remove `COMPONENT_` constants
-> Add `MAX_ACTION_ROW_BUTTONS` and `MAX_ACTION_ROW_SELECT_MENUS`

- Update Components Types

* Fix `ActionRow.isFull`

* Add types to thread rest endpoints

* 0.16.2 release
  • Loading branch information
cakedan authored Aug 25, 2021
1 parent 618e8c1 commit 211252f
Show file tree
Hide file tree
Showing 21 changed files with 1,397 additions and 401 deletions.
116 changes: 116 additions & 0 deletions examples/js/components/interactioncommentclient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
const { Constants, InteractionCommandClient, Utils } = require('../../../lib');
const { InteractionCallbackTypes, MessageFlags, Permissions } = Constants;
const { Components, ComponentActionRow } = Utils;


const guildId = '';
const token = '';
const interactionClient = new InteractionCommandClient(token);

interactionClient.add({
description: 'ping!',
name: 'ping',
guildIds: [guildId],
run: (context) => {
const actionRow = new ComponentActionRow();
actionRow.createButton({
label: 'ping, but clear buttons',
run: (componentContext) => componentContext.editOrRespond({content: 'pong from the button!', components: []}),
});
actionRow.createButton({
label: 'ping, but respond',
run: (componentContext) => {
return componentContext.respond(InteractionCallbackTypes.CHANNEL_MESSAGE_WITH_SOURCE, {
content: 'pong!',
flags: MessageFlags.EPHEMERAL,
});
},
});
return context.editOrRespond({content: 'pong!', components: [actionRow]});
},
});

interactionClient.add({
description: 'Click Test',
name: 'click-test',
guildIds: [guildId],
run: (context) => {
const components = new Components({
timeout: 5 * (60 * 1000),
onTimeout: () => context.editOrRespond({content: 'didnt click for 5 minutes', components: []}),
});
{
const actionRow = components.createActionRow();
actionRow.createButton({
label: 'click me',
run: (componentContext) => componentContext.editOrRespond({content: `clicked by ${componentContext.user}`, components: []}),
});
}
return context.editOrRespond({content: 'click the button', components});
},
});

interactionClient.add({
description: 'Give yourself a role',
name: 'give-role',
guildIds: [guildId],
disableDm: true,
permissions: [Permissions.MANAGE_ROLES],
permissionsClient: [Permissions.MANAGE_ROLES],
onPermissionsFail: (context, permissions) => context.editOrRespond('You need manage roles'),
onPermissionsFailClient: (context, permissions) => context.editOrRespond('The bot needs manage roles'),
onBefore: (context) => context.me.canEdit(context.member),
onCancel: (context) => context.editOrRespond('The bot cannot edit you, change some role hierachy or something'),
run: (context) => {
const components = new Components({
timeout: 5 * (60 * 1000),
onTimeout: () => context.editOrRespond({content: 'Choosing Expired', components: []}),
run: async (componentContext) => {
if (componentContext.userId !== context.userId || !context.values) {
// ignore the press because it wasnt from the initiator
return componentContext.respond(InteractionCallbackTypes.DEFERRED_UPDATE_MESSAGE);
}

const roleIds = context.values;
if (roleIds.length) {
if (context.me.canEdit(context.member)) {
for (let roleId of context.values) {
if (!context.member.roles.has(roleId) && context.me.canEditRole(roleId)) {
await context.member.addRole(roleId);
}
}
context.editOrRespond(`Ok, gave ${roleIds.length} roles to you`);
} else {
context.editOrRespond('Can\'t edit you anymore');
}
} else {
context.editOrRespond('choose some roles!');
}
},
});

if (context.guild) {
const rolesWeCanAdd = context.guild.roles.filter((role) => {
return !context.member.roles.has(roleId) && context.me.canEditRole(role);
});
if (rolesWeCanAdd.length) {
components.createSelectMenu({
placeholder: 'Choose',
options: rolesWeCanAdd.slice(0, 25).map((role) => {
return {
label: role.name,
value: role.id,
};
}),
});
}
}
return context.editOrRespond({content: 'choose a role', components, flags: MessageFlags.EPHEMERAL});
},
});


(async () => {
const cluster = await interactionClient.run();
console.log('running');
})();
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"dependencies": {
"@types/node": "^14.17.2",
"@types/node-fetch": "^2.5.10",
"detritus-client-rest": "^0.10.3",
"detritus-client-socket": "^0.8.2-beta.0",
"detritus-client-rest": "^0.10.4",
"detritus-client-socket": "^0.8.2",
"detritus-utils": "^0.4.0"
},
"description": "A Typescript NodeJS library to interact with Discord's API, both Rest and Gateway.",
Expand Down Expand Up @@ -56,5 +56,5 @@
"typedoc": "typedoc"
},
"types": "lib/index.d.ts",
"version": "0.16.1"
"version": "0.16.2"
}
16 changes: 16 additions & 0 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ import {
UserMe,
} from './structures';

import { Components, ComponentActionRow, ComponentActionRowData } from './utils';


interface GatewayOptions extends Gateway.SocketOptions, GatewayHandlerOptions {

Expand Down Expand Up @@ -379,6 +381,20 @@ export class ShardClient extends EventSpewer {
return oauth2Application;
}

hookComponents(
listenerId: string,
components: Components | Array<ComponentActionRowData | ComponentActionRow>,
timeout?: number,
): Components {
if (components instanceof Components) {
components.id = listenerId;
} else {
components = new Components({components, id: listenerId, timeout: timeout || 0});
}
this.gatewayHandler._componentHandler.insert(components);
return components;
}

isOwner(userId: string): boolean {
return this.owners.has(userId);
}
Expand Down
28 changes: 26 additions & 2 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,22 @@ export {

export const Package = Object.freeze({
URL: 'https://github.com/detritusjs/client',
VERSION: '0.16.1',
VERSION: '0.16.2',
});

export type Snowflake = number | string;


export const IS_TS_NODE = Symbol.for('ts-node.register.instance') in process;


export const DEFAULT_MAX_MEMBERS = 250000;
export const DEFAULT_MAX_PRESENCES = 5000;
export const DEFAULT_MAX_VIDEO_CHANNEL_USERS = 25;

export const LOCAL_GUILD_ID = '@me';

export const MAX_ACTION_ROW_BUTTONS = 5;
export const MAX_ACTION_ROW_SELECT_MENUS = 1;
export const MAX_ATTACHMENT_SIZE = 8 * 1024 * 1024;
export const MAX_ATTACHMENT_SIZE_PREMIUM = 50 * 1024 * 1024;
export const MAX_BITRATE = 96000;
Expand Down Expand Up @@ -950,6 +951,27 @@ export const PERMISSIONS_LURKER = [
Permissions.NONE,
);

export const PERMISSIONS_FOR_GUILD = [
Permissions.ADMINISTRATOR,
].reduce(
(permissions: bigint, permission: bigint) => permissions | permission,
Permissions.NONE,
);

export const PERMISSIONS_FOR_CHANNEL_TEXT = [
Permissions.ADMINISTRATOR,
].reduce(
(permissions: bigint, permission: bigint) => permissions | permission,
Permissions.NONE,
);

export const PERMISSIONS_FOR_CHANNEL_VOICE = [
Permissions.ADMINISTRATOR,
].reduce(
(permissions: bigint, permission: bigint) => permissions | permission,
Permissions.NONE,
);


export enum PlatformTypes {
BATTLENET = 'battlenet',
Expand Down Expand Up @@ -1541,6 +1563,7 @@ export const DiscordKeys = Object.freeze({
THREAD_METADATA: 'thread_metadata',
THREADS: 'threads',
THUMBNAIL: 'thumbnail',
TIMEOUT: 'timeout',
TIMESTAMP: 'timestamp',
TIMESTAMPS: 'timestamps',
TITLE: 'title',
Expand Down Expand Up @@ -1907,6 +1930,7 @@ export const DetritusKeys = Object.freeze({
[DiscordKeys.THREAD_METADATA]: 'threadMetadata',
[DiscordKeys.THREADS]: 'threads',
[DiscordKeys.THUMBNAIL]: 'thumbnail',
[DiscordKeys.TIMEOUT]: 'timeout',
[DiscordKeys.TIMESTAMP]: 'timestamp',
[DiscordKeys.TIMESTAMPS]: 'timestamps',
[DiscordKeys.TITLE]: 'title',
Expand Down
88 changes: 88 additions & 0 deletions src/gateway/componenthandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { Timers } from 'detritus-utils';

import { BaseCollection } from '../collections';
import { Interaction, InteractionDataComponent } from '../structures';
import { Components, ComponentContext } from '../utils';


export class ComponentHandler {
listeners = new BaseCollection<string, Components>();

delete(listenerId: string): boolean {
if (this.listeners.has(listenerId)) {
const listener = this.listeners.get(listenerId)!;
if (listener._timeout) {
listener._timeout.stop();
}
return this.listeners.delete(listenerId);
}
return false;
}

async execute(interaction: Interaction): Promise<void> {
if (!this.listeners.length || !interaction.isFromMessageComponent || !interaction.message || !interaction.data) {
return;
}
const message = interaction.message;
const data = interaction.data as InteractionDataComponent;

const listener = this.listeners.get(message.interaction?.id || message.id) || this.listeners.get(message.id);
if (listener) {
try {
if (typeof(listener.run) === 'function') {
const context = new ComponentContext(interaction);
await Promise.resolve(listener.run(context));
}
} catch(error) {

}

for (let actionRow of listener.components) {
const component = actionRow.components.find((c) => c.customId === data.customId);
if (component) {
try {
if (typeof(component.run) === 'function') {
const context = new ComponentContext(interaction);
await Promise.resolve(component.run(context));
}
} catch(error) {

}
break;
}
}
}
}

insert(listener: Components) {
const listenerId = listener.id;
if (listenerId) {
if (this.listeners.has(listenerId)) {
const oldListener = this.listeners.get(listenerId)!;
if (oldListener._timeout) {
oldListener._timeout.stop();
}
this.delete(listenerId);
}

if (listener.timeout) {
const timeout = listener._timeout = new Timers.Timeout();
timeout.start(listener.timeout, async () => {
if (this.listeners.get(listenerId) === listener) {
this.delete(listenerId);

try {
if (typeof(listener.onTimeout) === 'function') {
await Promise.resolve(listener.onTimeout());
}
} catch(error) {

}
}
});
}

this.listeners.set(listenerId, listener);
}
}
}
Loading

0 comments on commit 211252f

Please sign in to comment.