Merge pull request #5 from discordeno/master

sync master
This commit is contained in:
ITOH
2021-01-23 20:46:43 +01:00
committed by GitHub
12 changed files with 150 additions and 35 deletions

View File

@@ -1,4 +1,4 @@
import { eventHandlers, setBotID } from "../../bot.ts";
import { eventHandlers, setApplicationID, setBotID } from "../../bot.ts";
import {
DiscordPayload,
PresenceUpdatePayload,
@@ -24,6 +24,7 @@ export async function handleInternalReady(
const payload = data.d as ReadyPayload;
setBotID(payload.user.id);
setApplicationID(payload.application.id);
// Triggered on each shard
eventHandlers.shardReady?.(shardID);

View File

@@ -9,6 +9,7 @@ import {
GetMessagesAfter,
GetMessagesAround,
GetMessagesBefore,
InvitePayload,
MessageContent,
MessageCreateOptions,
Permission,
@@ -19,6 +20,7 @@ import {
import { endpoints } from "../../util/constants.ts";
import {
botHasChannelPermissions,
botHasPermission,
calculateBits,
} from "../../util/permissions.ts";
import { cacheHandlers } from "../controllers/cache.ts";
@@ -301,6 +303,39 @@ export async function createInvite(
return RequestManager.post(endpoints.CHANNEL_INVITES(channelID), options);
}
/** Returns an invite for the given code. */
export function getInvite(inviteCode: string) {
return RequestManager.get(endpoints.INVITE(inviteCode)) as Promise<
InvitePayload
>;
}
/** Deletes an invite for the given code. Requires `MANAGE_CHANNELS` or `MANAGE_GUILD` permission */
export async function deleteInvite(
channelID: string,
inviteCode: string,
) {
const hasPerm = await botHasChannelPermissions(channelID, [
"MANAGE_CHANNELS",
]);
if (!hasPerm) {
const channel = await cacheHandlers.get("channels", channelID);
const hasManageGuildPerm = await botHasPermission(channel!.guildID, [
"MANAGE_GUILD",
]);
if (!hasManageGuildPerm) {
throw new Error(Errors.MISSING_MANAGE_CHANNELS);
}
}
return RequestManager.delete(endpoints.INVITE(inviteCode)) as Promise<
InvitePayload
>;
}
/** Gets the webhooks for this channel. Requires MANAGE_WEBHOOKS */
export async function getChannelWebhooks(channelID: string) {
const hasManageWebhooksPerm = await botHasChannelPermissions(

View File

@@ -729,6 +729,11 @@ export function leaveGuild(guildID: string) {
return RequestManager.delete(endpoints.GUILD_LEAVE(guildID));
}
/** Returns an array of voice regions that can be used when creating servers. */
export function getAvailableVoiceRegions() {
return RequestManager.get(endpoints.VOICE_REGIONS);
}
/** Returns a list of voice region objects for the guild. Unlike the similar /voice route, this returns VIP servers when the guild is VIP-enabled. */
export function getVoiceRegions(guildID: string) {
return RequestManager.get(endpoints.GUILD_REGIONS(guildID));
@@ -767,13 +772,23 @@ export function getGuild(guildID: string, counts = true) {
}
/** Returns the guild template if it exists */
export async function getTemplate(templateCode: string) {
const result = await RequestManager.get(
endpoints.GUILD_TEMPLATE(templateCode),
) as GuildTemplate;
const template = await structures.createTemplate(result);
return template;
}
/**
* Returns the guild template if it exists
* @deprecated will get removed in v11 use `getTemplate` instead
*/
export function getGuildTemplate(
guildID: string,
templateCode: string,
) {
return RequestManager.get(
`${endpoints.GUILD_TEMPLATES(guildID)}/${templateCode}`,
) as Promise<Template>;
return getTemplate(templateCode);
}
/**

View File

@@ -1,11 +1,13 @@
import {
channelOverwriteHasPermission,
createInvite,
deleteInvite,
deleteMessages,
editChannel,
followChannel,
getChannelInvites,
getChannelWebhooks,
getInvite,
getMessage,
getMessages,
getPins,
@@ -40,6 +42,7 @@ import {
emojiURL,
fetchMembers,
getAuditLogs,
getAvailableVoiceRegions,
getBan,
getBans,
getChannel,
@@ -57,6 +60,7 @@ import {
getMembersByQuery,
getPruneCount,
getRoles,
getTemplate,
getUser,
getVanityURL,
getVoiceRegions,
@@ -131,6 +135,8 @@ export let handlers = {
getPins,
isChannelSynced,
sendMessage,
getInvite,
deleteInvite,
startTyping,
// Gateway handler
@@ -171,9 +177,11 @@ export let handlers = {
getGuildPreview,
getGuildTemplate,
getGuildTemplates,
getAvailableVoiceRegions,
getIntegrations,
getInvites,
getMember,
getTemplate,
getMembersByQuery,
getPruneCount,
getRoles,

View File

@@ -1,4 +1,4 @@
import { botID } from "../../bot.ts";
import { applicationID } from "../../bot.ts";
import { RequestManager } from "../../rest/request_manager.ts";
import {
CreateSlashCommandOptions,
@@ -206,8 +206,8 @@ export function createSlashCommand(options: CreateSlashCommandOptions) {
return RequestManager.post(
options.guildID
? endpoints.COMMANDS_GUILD(botID, options.guildID)
: endpoints.COMMANDS(botID),
? endpoints.COMMANDS_GUILD(applicationID, options.guildID)
: endpoints.COMMANDS(applicationID),
{
...options,
},
@@ -219,8 +219,8 @@ export function getSlashCommands(guildID?: string) {
// TODO: Should this be a returned as a collection?
return RequestManager.get(
guildID
? endpoints.COMMANDS_GUILD(botID, guildID)
: endpoints.COMMANDS(botID),
? endpoints.COMMANDS_GUILD(applicationID, guildID)
: endpoints.COMMANDS(applicationID),
);
}
@@ -230,8 +230,8 @@ export function getSlashCommands(guildID?: string) {
export function upsertSlashCommand(options: UpsertSlashCommandOptions) {
return RequestManager.post(
options.guildID
? endpoints.COMMANDS_GUILD_ID(botID, options.id, options.guildID)
: endpoints.COMMANDS_ID(botID, options.id),
? endpoints.COMMANDS_GUILD_ID(applicationID, options.id, options.guildID)
: endpoints.COMMANDS_ID(applicationID, options.id),
{
...options,
},
@@ -242,8 +242,8 @@ export function upsertSlashCommand(options: UpsertSlashCommandOptions) {
export function editSlashCommand(options: EditSlashCommandOptions) {
return RequestManager.patch(
options.guildID
? endpoints.COMMANDS_GUILD_ID(botID, options.id, options.guildID)
: endpoints.COMMANDS_ID(botID, options.id),
? endpoints.COMMANDS_GUILD_ID(applicationID, options.id, options.guildID)
: endpoints.COMMANDS_ID(applicationID, options.id),
{
...options,
},
@@ -252,8 +252,12 @@ export function editSlashCommand(options: EditSlashCommandOptions) {
/** Deletes a slash command. */
export function deleteSlashCommand(id: string, guildID?: string) {
if (!guildID) return RequestManager.delete(endpoints.COMMANDS_ID(botID, id));
return RequestManager.delete(endpoints.COMMANDS_GUILD_ID(botID, id, guildID));
if (!guildID) {
return RequestManager.delete(endpoints.COMMANDS_ID(applicationID, id));
}
return RequestManager.delete(
endpoints.COMMANDS_GUILD_ID(applicationID, id, guildID),
);
}
/**
@@ -269,7 +273,7 @@ export function executeSlashCommand(
) {
// If its already been executed, we need to send a followup response
if (cache.executedSlashCommands.has(token)) {
return RequestManager.post(endpoints.WEBHOOK(botID, token), {
return RequestManager.post(endpoints.WEBHOOK(applicationID, token), {
...options,
});
}
@@ -298,11 +302,11 @@ export function deleteSlashResponse(
) {
if (!messageID) {
return RequestManager.delete(
endpoints.INTERACTION_ORIGINAL_ID_TOKEN(botID, token),
endpoints.INTERACTION_ORIGINAL_ID_TOKEN(applicationID, token),
);
}
return RequestManager.delete(
endpoints.INTERACTION_ID_TOKEN_MESSAGEID(botID, token, messageID),
endpoints.INTERACTION_ID_TOKEN_MESSAGEID(applicationID, token, messageID),
);
}
@@ -312,7 +316,7 @@ export function editSlashResponse(
options: EditSlashResponseOptions,
) {
return RequestManager.patch(
endpoints.INTERACTION_ORIGINAL_ID_TOKEN(botID, token),
endpoints.INTERACTION_ORIGINAL_ID_TOKEN(applicationID, token),
options,
);
}

View File

@@ -10,6 +10,7 @@ import { spawnShards } from "./ws/shard_manager.ts";
export let authorization = "";
export let botID = "";
export let applicationID = "";
export let eventHandlers: EventHandlers = {};
@@ -74,6 +75,11 @@ export function setBotID(id: string) {
if (botID !== id) botID = id;
}
/** INTERNAL LIB function used to set the application ID once the READY event is sent by Discord. */
export function setApplicationID(id: string) {
if (applicationID !== id) applicationID = id;
}
// BIG BRAIN BOT STUFF ONLY BELOW THIS
/**

28
src/types/invite.ts Normal file
View File

@@ -0,0 +1,28 @@
import { Guild } from "../api/structures/mod.ts";
import { ChannelCreatePayload } from "./channel.ts";
import { UserPayload } from "./guild.ts";
/** https://discord.com/developers/docs/resources/invite#invite-object */
export interface InvitePayload {
/** the invite code (unique ID) */
code: string;
/** the guild this invite is for */
guild?: Partial<Guild>;
/** the channel this invite is for */
channel: Partial<ChannelCreatePayload>;
/** the user who created the invite */
inviter?: UserPayload;
/** the target user for this invite */
target_user?: Partial<UserPayload>;
/** the type of user target for this invite */
target_user_type?: InviteTargetUserTypes;
/** approximate count of online members (only present when target_user is set) */
approximate_presence_count?: number;
/** approximate count of total members */
approximate_member_count: number;
}
/** https://discord.com/developers/docs/resources/invite#invite-resource */
export enum InviteTargetUserTypes {
STREAM = 1,
}

View File

@@ -6,6 +6,7 @@ export * from "./errors.ts";
export * from "./fetch.ts";
export * from "./guild.ts";
export * from "./interactions.ts";
export * from "./invite.ts";
export * from "./member.ts";
export * from "./message.ts";
export * from "./options.ts";

View File

@@ -10,9 +10,14 @@ export interface CacheData {
members: Collection<string, Member>;
unavailableGuilds: Collection<string, number>;
presences: Collection<string, PresenceUpdatePayload>;
// TODO: The type Collection's second provided generic [function] should have a definite shape.
// deno-lint-ignore ban-types
fetchAllMembersProcessingRequests: Collection<string, Function>;
fetchAllMembersProcessingRequests: Collection<
string,
(
value:
| Collection<string, Member>
| PromiseLike<Collection<string, Member>>,
) => void
>;
executedSlashCommands: Collection<string, string>;
}

View File

@@ -117,6 +117,9 @@ export const endpoints = {
GUILD_TEMPLATES: (guildID: string) => `${GUILDS_BASE(guildID)}/templates`,
GUILD_PREVIEW: (guildID: string) => `${GUILDS_BASE(guildID)}/preview`,
// Voice
VOICE_REGIONS: `${baseEndpoints.BASE_URL}/voice/regions`,
INVITE: (inviteCode: string) =>
`${baseEndpoints.BASE_URL}/invites/${inviteCode}`,
@@ -132,14 +135,18 @@ export const endpoints = {
`${baseEndpoints.BASE_URL}/webhooks/${webhookID}/${token}/github`,
// Application Endpoints
COMMANDS: (botID: string) =>
`${baseEndpoints.BASE_URL}/applications/${botID}/commands`,
COMMANDS_GUILD: (botID: string, guildID: string) =>
`${baseEndpoints.BASE_URL}/applications/${botID}/guilds/${guildID}/commands`,
COMMANDS_ID: (botID: string, commandID: string) =>
`${baseEndpoints.BASE_URL}/applications/${botID}/commands/${commandID}`,
COMMANDS_GUILD_ID: (botID: string, commandID: string, guildID: string) =>
`${baseEndpoints.BASE_URL}/applications/${botID}/guilds/${guildID}/commands/${commandID}`,
COMMANDS: (applicationID: string) =>
`${baseEndpoints.BASE_URL}/applications/${applicationID}/commands`,
COMMANDS_GUILD: (applicationID: string, guildID: string) =>
`${baseEndpoints.BASE_URL}/applications/${applicationID}/guilds/${guildID}/commands`,
COMMANDS_ID: (applicationID: string, commandID: string) =>
`${baseEndpoints.BASE_URL}/applications/${applicationID}/commands/${commandID}`,
COMMANDS_GUILD_ID: (
applicationID: string,
commandID: string,
guildID: string,
) =>
`${baseEndpoints.BASE_URL}/applications/${applicationID}/guilds/${guildID}/commands/${commandID}`,
// Interaction Endpoints
INTERACTION_ID_TOKEN: (interactionID: string, token: string) =>

View File

@@ -67,8 +67,11 @@ export function createShard(
}
};
ws.onerror = ({ timeStamp }) => {
eventHandlers.debug?.({ type: "wsError", data: { timeStamp } });
ws.onerror = (errorEvent) => {
eventHandlers.debug?.({
type: "wsError",
data: { shardID: basicShard.id, ...errorEvent },
});
};
ws.onmessage = ({ data: message }) => {

View File

@@ -1,5 +1,6 @@
import { controllers } from "../api/controllers/mod.ts";
import { Guild } from "../api/structures/guild.ts";
import { Member } from "../api/structures/mod.ts";
import { eventHandlers, IdentifyPayload } from "../bot.ts";
import {
DiscordBotGatewayData,
@@ -8,6 +9,7 @@ import {
GatewayOpcode,
} from "../types/mod.ts";
import { cache } from "../util/cache.ts";
import { Collection } from "../util/collection.ts";
import { BotStatusRequest, delay } from "../util/utils.ts";
import {
botGatewayStatusRequest,
@@ -90,9 +92,9 @@ export async function handleDiscordPayload(
export function requestAllMembers(
guild: Guild,
// TODO: The parameter "resolve" should have a "stronger" type.
// deno-lint-ignore ban-types
resolve: Function,
resolve: (
value: Collection<string, Member> | PromiseLike<Collection<string, Member>>,
) => void,
options?: FetchMembersOptions,
) {
const nonce = `${guild.id}-${Date.now()}`;