mirror of
https://github.com/discordeno/discordeno.git
synced 2026-06-04 09:50:07 +00:00
Merge branch 'main' into v12
This commit is contained in:
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -1 +1 @@
|
||||
* @Skillz4Killz @itohatweb
|
||||
* @Skillz4Killz @itohatweb @ayntee
|
||||
|
||||
@@ -65,7 +65,7 @@ unofficial templates:
|
||||
|
||||
- [Discordeno Template (official)](https://github.com/discordeno/template)
|
||||
- [Serverless Slash Commands Template
|
||||
(official)](https://github.com/discordeno/slash-commands-template)
|
||||
(official)](https://github.com/discordeno/serverless-deno-deploy-template)
|
||||
- [Add Your Own!](https://github.com/discordeno/discordeno/pulls)
|
||||
|
||||
## Links
|
||||
|
||||
143
src/cache.ts
143
src/cache.ts
@@ -8,6 +8,12 @@ import type { PresenceUpdate } from "./types/activity/presence_update.ts";
|
||||
import type { Emoji } from "./types/emojis/emoji.ts";
|
||||
import { DiscordenoThread } from "./util/transformers/channel_to_thread.ts";
|
||||
import { Collection } from "./util/collection.ts";
|
||||
import { Channel } from "./types/channels/channel.ts";
|
||||
import { Guild } from "./types/guilds/guild.ts";
|
||||
import { GuildMemberWithUser } from "./types/members/guild_member.ts";
|
||||
import { Message } from "./types/messages/message.ts";
|
||||
import { Role } from "./types/permissions/role.ts";
|
||||
import { VoiceState } from "./types/voice/voice_state.ts";
|
||||
|
||||
export const cache = {
|
||||
isReady: false,
|
||||
@@ -37,6 +43,21 @@ export const cache = {
|
||||
dispatchedGuildIds: new Set<bigint>(),
|
||||
dispatchedChannelIds: new Set<bigint>(),
|
||||
threads: new Collection<bigint, DiscordenoThread>(),
|
||||
/** ADVANCED USER ONLY: Please ask for help before modifying these. The properties that you want to use for your bot's structures. If you do not set any properties, all properties will be used by default. */
|
||||
requiredStructureProperties: {
|
||||
/** Only these properties will be added to memory for your channels. */
|
||||
channels: new Set<keyof Channel>(),
|
||||
/** Only these properties will be added to memory for your guilds. */
|
||||
guilds: new Set<keyof Guild>(),
|
||||
/** Only these properties will be added to memory for your members. */
|
||||
members: new Set<keyof GuildMemberWithUser>(),
|
||||
/** Only these properties will be added to memory for your messages. */
|
||||
messages: new Set<keyof Message>(),
|
||||
/** Only these properties will be added to memory for your roles. */
|
||||
roles: new Set<keyof Role>(),
|
||||
/** Only these properties will be added to memory for your voice states. */
|
||||
voiceStates: new Set<keyof VoiceState>(),
|
||||
},
|
||||
};
|
||||
|
||||
function messageSweeper(message: DiscordenoMessage) {
|
||||
@@ -149,58 +170,80 @@ async function get(table: TableName, key: bigint) {
|
||||
return cache[table].get(key);
|
||||
}
|
||||
|
||||
function forEach(
|
||||
table: "threads",
|
||||
callback: (value: DiscordenoThread, key: bigint, map: Map<bigint, DiscordenoThread>) => unknown
|
||||
): void;
|
||||
function forEach(
|
||||
table: "guilds",
|
||||
callback: (value: DiscordenoGuild, key: bigint, map: Map<bigint, DiscordenoGuild>) => unknown
|
||||
): void;
|
||||
function forEach(
|
||||
table: "unavailableGuilds",
|
||||
callback: (value: number, key: bigint, map: Map<bigint, number>) => unknown
|
||||
): void;
|
||||
function forEach(
|
||||
table: "channels",
|
||||
callback: (value: DiscordenoChannel, key: bigint, map: Map<bigint, DiscordenoChannel>) => unknown
|
||||
): void;
|
||||
function forEach(
|
||||
table: "messages",
|
||||
callback: (value: DiscordenoMessage, key: bigint, map: Map<bigint, DiscordenoMessage>) => unknown
|
||||
): void;
|
||||
function forEach(
|
||||
table: "members",
|
||||
callback: (value: DiscordenoMember, key: bigint, map: Map<bigint, DiscordenoMember>) => unknown
|
||||
): void;
|
||||
function forEach(table: TableName, callback: (value: any, key: bigint, map: Map<bigint, any>) => unknown) {
|
||||
return cache[table].forEach(callback);
|
||||
// callback: (value: DiscordenoThread, key: bigint, map: Map<bigint, DiscordenoThread>) => void
|
||||
async function forEach(type: "DELETE_MESSAGES_FROM_CHANNEL", options: { channelId: bigint }): Promise<void>;
|
||||
async function forEach(type: "DELETE_MESSAGES_FROM_GUILD", options: { guildId: bigint }): Promise<void>;
|
||||
async function forEach(type: "DELETE_CHANNELS_FROM_GUILD", options: { guildId: bigint }): Promise<void>;
|
||||
async function forEach(type: "DELETE_GUILD_FROM_MEMBER", options: { guildId: bigint }): Promise<void>;
|
||||
async function forEach(type: "DELETE_ROLE_FROM_MEMBER", options: { guildId: bigint; roleId: bigint }): Promise<void>;
|
||||
async function forEach(
|
||||
type:
|
||||
| "DELETE_MESSAGES_FROM_CHANNEL"
|
||||
| "DELETE_MESSAGES_FROM_GUILD"
|
||||
| "DELETE_CHANNELS_FROM_GUILD"
|
||||
| "DELETE_GUILD_FROM_MEMBER"
|
||||
| "DELETE_ROLE_FROM_MEMBER",
|
||||
options?: Record<string, unknown>
|
||||
) {
|
||||
if (type === "DELETE_MESSAGES_FROM_CHANNEL") {
|
||||
cache.messages.forEach((message) => {
|
||||
if (message.channelId === options?.channelId) cache.messages.delete(message.id);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === "DELETE_MESSAGES_FROM_GUILD") {
|
||||
cache.messages.forEach((message) => {
|
||||
if (message.guildId === options?.guildId) cache.messages.delete(message.id);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === "DELETE_CHANNELS_FROM_GUILD") {
|
||||
cache.channels.forEach((channel) => {
|
||||
if (channel.guildId === options?.guildId) cache.channels.delete(channel.id);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === "DELETE_GUILD_FROM_MEMBER") {
|
||||
cache.members.forEach((member) => {
|
||||
if (!member.guilds.has(options?.guildId as bigint)) return;
|
||||
|
||||
member.guilds.delete(options?.guildId as bigint);
|
||||
|
||||
if (!member.guilds.size) {
|
||||
return cache.members.delete(member.id);
|
||||
}
|
||||
|
||||
cache.members.set(member.id, member);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === "DELETE_ROLE_FROM_MEMBER") {
|
||||
cache.members.forEach((member) => {
|
||||
// Not in the relevant guild so just skip
|
||||
if (!member.guilds.has(options?.guildId as bigint)) return;
|
||||
|
||||
const guildMember = member.guilds.get(options?.guildId as bigint)!;
|
||||
|
||||
guildMember.roles = guildMember.roles.filter((id) => id !== (options?.roleId as bigint));
|
||||
cache.members.set(member.id, member);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async function filter(
|
||||
table: "threads",
|
||||
callback: (value: DiscordenoThread, key: bigint) => boolean
|
||||
): Promise<Collection<bigint, DiscordenoThread>>;
|
||||
async function filter(
|
||||
table: "guilds",
|
||||
callback: (value: DiscordenoGuild, key: bigint) => boolean
|
||||
): Promise<Collection<bigint, DiscordenoGuild>>;
|
||||
async function filter(
|
||||
table: "unavailableGuilds",
|
||||
callback: (value: number, key: bigint) => boolean
|
||||
): Promise<Collection<bigint, number>>;
|
||||
async function filter(
|
||||
table: "channels",
|
||||
callback: (value: DiscordenoChannel, key: bigint) => boolean
|
||||
): Promise<Collection<bigint, DiscordenoChannel>>;
|
||||
async function filter(
|
||||
table: "messages",
|
||||
callback: (value: DiscordenoMessage, key: bigint) => boolean
|
||||
): Promise<Collection<bigint, DiscordenoMessage>>;
|
||||
async function filter(
|
||||
table: "members",
|
||||
callback: (value: DiscordenoMember, key: bigint) => boolean
|
||||
type: "GET_MEMBERS_IN_GUILD",
|
||||
options: { guildId: bigint }
|
||||
): Promise<Collection<bigint, DiscordenoMember>>;
|
||||
async function filter(table: TableName, callback: (value: any, key: bigint) => boolean) {
|
||||
return cache[table].filter(callback);
|
||||
async function filter(
|
||||
type: "GET_MEMBERS_IN_GUILD",
|
||||
options?: Record<string, unknown>
|
||||
): Promise<Collection<bigint, DiscordenoMember> | undefined> {
|
||||
if (type === "GET_MEMBERS_IN_GUILD") {
|
||||
return cache.members.filter((member) => member.guilds.has(options?.guildId as bigint));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,7 @@ export async function handleChannelDelete(data: DiscordGatewayPayload) {
|
||||
].includes(payload.type)
|
||||
) {
|
||||
await cacheHandlers.delete("channels", snowflakeToBigint(payload.id));
|
||||
cacheHandlers.forEach("messages", (message) => {
|
||||
eventHandlers.debug?.("loop", `Running forEach messages loop in CHANNEL_DELTE file.`);
|
||||
if (message.channelId === snowflakeToBigint(payload.id)) {
|
||||
cacheHandlers.delete("messages", message.id);
|
||||
}
|
||||
});
|
||||
await cacheHandlers.forEach("DELETE_MESSAGES_FROM_CHANNEL", { channelId: snowflakeToBigint(payload.id) });
|
||||
}
|
||||
|
||||
await cacheHandlers.delete("channels", snowflakeToBigint(payload.id));
|
||||
|
||||
@@ -11,12 +11,7 @@ export async function handleThreadDelete(data: DiscordGatewayPayload) {
|
||||
if (!cachedChannel) return;
|
||||
|
||||
await cacheHandlers.delete("threads", snowflakeToBigint(payload.id));
|
||||
cacheHandlers.forEach("messages", (message) => {
|
||||
eventHandlers.debug?.("loop", `Running forEach messages loop in THREAD_DELETE file.`);
|
||||
if (message.channelId === snowflakeToBigint(payload.id)) {
|
||||
cacheHandlers.delete("messages", message.id);
|
||||
}
|
||||
});
|
||||
await cacheHandlers.forEach("DELETE_MESSAGES_FROM_CHANNEL", { channelId: snowflakeToBigint(payload.id) });
|
||||
|
||||
eventHandlers.threadDelete?.(cachedChannel);
|
||||
}
|
||||
|
||||
@@ -23,30 +23,9 @@ export async function handleGuildDelete(data: DiscordGatewayPayload, shardId: nu
|
||||
eventHandlers.guildDelete?.(guild);
|
||||
}
|
||||
|
||||
cacheHandlers.forEach("messages", (message) => {
|
||||
eventHandlers.debug?.("loop", `1. Running forEach messages loop in CHANNEL_DELTE file.`);
|
||||
if (message.guildId === guild.id) {
|
||||
cacheHandlers.delete("messages", message.id);
|
||||
}
|
||||
});
|
||||
|
||||
cacheHandlers.forEach("channels", (channel) => {
|
||||
eventHandlers.debug?.("loop", `2. Running forEach channels loop in CHANNEL_DELTE file.`);
|
||||
if (channel.guildId === guild.id) {
|
||||
cacheHandlers.delete("channels", channel.id);
|
||||
}
|
||||
});
|
||||
|
||||
cacheHandlers.forEach("members", (member) => {
|
||||
eventHandlers.debug?.("loop", `3. Running forEach members loop in CHANNEL_DELTE file.`);
|
||||
if (!member.guilds.has(guild.id)) return;
|
||||
|
||||
member.guilds.delete(guild.id);
|
||||
|
||||
if (!member.guilds.size) {
|
||||
return cacheHandlers.delete("members", member.id);
|
||||
}
|
||||
|
||||
cacheHandlers.set("members", member.id, member);
|
||||
});
|
||||
await Promise.all([
|
||||
cacheHandlers.forEach("DELETE_MESSAGES_FROM_GUILD", { guildId: guild.id }),
|
||||
cacheHandlers.forEach("DELETE_CHANNELS_FROM_GUILD", { guildId: guild.id }),
|
||||
cacheHandlers.forEach("DELETE_GUILD_FROM_MEMBER", { guildId: guild.id }),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export async function handleGuildMembersChunk(data: DiscordGatewayPayload) {
|
||||
return resolve(new Collection(members.map((m) => [m.id, m])));
|
||||
}
|
||||
|
||||
return resolve(await cacheHandlers.filter("members", (m) => m.guilds.has(guildId)));
|
||||
return resolve(await cacheHandlers.filter("GET_MEMBERS_IN_GUILD", { guildId }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,18 +17,5 @@ export async function handleGuildRoleDelete(data: DiscordGatewayPayload) {
|
||||
if (cachedRole) eventHandlers.roleDelete?.(guild, cachedRole);
|
||||
|
||||
// For bots without GUILD_MEMBERS member.roles is never updated breaking permissions checking.
|
||||
cacheHandlers.forEach("members", (member) => {
|
||||
eventHandlers.debug?.("loop", `1. Running forEach members loop in GUILD_ROLE_DELETE file.`);
|
||||
// Not in the relevant guild so just skip.
|
||||
if (!member.guilds.has(guild.id)) return;
|
||||
|
||||
member.guilds.forEach((g) => {
|
||||
eventHandlers.debug?.("loop", `2. Running forEach loop in CHANNEL_DELTE file.`);
|
||||
// Member does not have this role
|
||||
if (!g.roles.includes(roleId)) return;
|
||||
// Remove this role from the members cache
|
||||
g.roles = g.roles.filter((id) => id !== roleId);
|
||||
cacheHandlers.set("members", member.id, member);
|
||||
});
|
||||
});
|
||||
await cacheHandlers.forEach("DELETE_ROLE_FROM_MEMBER", { guildId: guild.id, roleId });
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { cache } from "../../cache.ts";
|
||||
|
||||
/** Gets an array of all the channels ids that are the children of this category. */
|
||||
export async function categoryChildren(id: bigint) {
|
||||
return await cacheHandlers.filter("channels", (channel) => channel.parentId === id);
|
||||
/** Gets an array of all the channels ids that are the children of this category.
|
||||
* ⚠️ This does not work for custom cache users!
|
||||
*/
|
||||
export function categoryChildren(parentChannelId: bigint) {
|
||||
return cache.channels.filter((channel) => channel.parentId === parentChannelId);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ export async function deleteChannel(channelId: bigint, reason?: string) {
|
||||
throw new Error(Errors.UPDATES_CHANNEL_CANNOT_BE_DELETED);
|
||||
}
|
||||
|
||||
// TODO(threads): check if this requires guild perms or channel is enough
|
||||
await requireBotGuildPermissions(guild, ["MANAGE_CHANNELS"]);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import { endpoints } from "../../util/constants.ts";
|
||||
import { calculateBits, requireOverwritePermissions } from "../../util/permissions.ts";
|
||||
import { snakelize } from "../../util/utils.ts";
|
||||
|
||||
//TODO: implement DM group channel edit
|
||||
/** Update a channel's settings. Requires the `MANAGE_CHANNELS` permission for the guild. */
|
||||
export async function editChannel(channelId: bigint, options: ModifyChannel, reason?: string) {
|
||||
const channel = await cacheHandlers.get("channels", channelId);
|
||||
|
||||
@@ -4,8 +4,7 @@ import { Errors } from "../../../types/discordeno/errors.ts";
|
||||
import { endpoints } from "../../../util/constants.ts";
|
||||
import { requireBotChannelPermissions } from "../../../util/permissions.ts";
|
||||
|
||||
/** Adds a user to a thread. Requires the ability to send messages in the thread. Requires the thread is not archived.
|
||||
*/
|
||||
/** Adds a user to a thread. Requires the ability to send messages in the thread. Requires the thread is not archived. */
|
||||
export async function addToThread(threadId: bigint, userId: bigint) {
|
||||
const thread = await cacheHandlers.get("threads", threadId);
|
||||
if (thread) {
|
||||
@@ -19,5 +18,5 @@ export async function addToThread(threadId: bigint, userId: bigint) {
|
||||
if (channel) await requireBotChannelPermissions(channel, ["SEND_MESSAGES"]);
|
||||
}
|
||||
|
||||
return await rest.runMethod("put", endpoints.THREAD_USER(threadId, userId));
|
||||
return await rest.runMethod<undefined>("put", endpoints.THREAD_USER(threadId, userId));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { editThread } from "./edit_thread.ts";
|
||||
|
||||
/** Sets a thread channel to be archived. */
|
||||
export function archiveThread(threadId: bigint) {
|
||||
return editThread(threadId, { archived: true });
|
||||
export async function archiveThread(threadId: bigint) {
|
||||
return await editThread(threadId, { archived: true });
|
||||
}
|
||||
|
||||
@@ -11,5 +11,5 @@ export async function deleteThread(threadId: bigint, reason?: string) {
|
||||
if (channel?.guildId) await requireBotGuildPermissions(channel.guildId, ["MANAGE_THREADS"]);
|
||||
}
|
||||
|
||||
return await rest.runMethod("delete", endpoints.CHANNEL_BASE(threadId), { reason });
|
||||
return await rest.runMethod<undefined>("delete", endpoints.CHANNEL_BASE(threadId), { reason });
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { cacheHandlers } from "../../../cache.ts";
|
||||
import { rest } from "../../../rest/rest.ts";
|
||||
import { ThreadMember } from "../../../types/channels/threads/thread_member.ts";
|
||||
import { Errors } from "../../../types/discordeno/errors.ts";
|
||||
import { DiscordGatewayIntents } from "../../../types/gateway/gateway_intents.ts";
|
||||
import { Collection } from "../../../util/collection.ts";
|
||||
import { endpoints } from "../../../util/constants.ts";
|
||||
import { botHasChannelPermissions } from "../../../util/permissions.ts";
|
||||
import { threadMemberModified } from "../../../util/transformers/thread_member_modified.ts";
|
||||
import { ws } from "../../../ws/ws.ts";
|
||||
|
||||
/** Returns thread members objects that are members of the thread. */
|
||||
@@ -20,5 +23,9 @@ export async function getThreadMembers(threadId: bigint) {
|
||||
throw new Error(Errors.CANNOT_GET_MEMBERS_OF_AN_UNJOINED_PRIVATE_THREAD);
|
||||
}
|
||||
|
||||
return await rest.runMethod("get", endpoints.THREAD_MEMBERS(threadId));
|
||||
const result = await rest.runMethod<ThreadMember[]>("get", endpoints.THREAD_MEMBERS(threadId));
|
||||
|
||||
const members = result.map((member) => threadMemberModified(member));
|
||||
|
||||
return new Collection(members.map((member) => [member.id, member]));
|
||||
}
|
||||
|
||||
@@ -10,5 +10,5 @@ export async function joinThread(threadId: bigint) {
|
||||
throw new Error(Errors.CANNOT_ADD_USER_TO_ARCHIVED_THREADS);
|
||||
}
|
||||
|
||||
return await rest.runMethod("put", endpoints.THREAD_ME(threadId));
|
||||
return await rest.runMethod<undefined>("put", endpoints.THREAD_ME(threadId));
|
||||
}
|
||||
|
||||
@@ -8,5 +8,5 @@ export async function leaveThread(threadId: bigint) {
|
||||
const thread = await cacheHandlers.get("threads", threadId);
|
||||
if (thread?.archived) throw new Error(Errors.CANNOT_LEAVE_ARCHIVED_THREAD);
|
||||
|
||||
return await rest.runMethod("delete", endpoints.THREAD_ME(threadId));
|
||||
return await rest.runMethod<undefined>("delete", endpoints.THREAD_ME(threadId));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { editThread } from "./edit_thread.ts";
|
||||
|
||||
/** Sets a thread channel to be locked. */
|
||||
export function lockThread(threadId: bigint) {
|
||||
return editThread(threadId, { locked: true });
|
||||
export async function lockThread(threadId: bigint) {
|
||||
return await editThread(threadId, { locked: true });
|
||||
}
|
||||
|
||||
@@ -17,5 +17,5 @@ export async function removeThreadMember(threadId: bigint, userId: bigint) {
|
||||
}
|
||||
}
|
||||
|
||||
return await rest.runMethod("delete", endpoints.THREAD_USER(threadId, userId));
|
||||
return await rest.runMethod<undefined>("delete", endpoints.THREAD_USER(threadId, userId));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { cacheHandlers } from "../../../cache.ts";
|
||||
import { rest } from "../../../rest/rest.ts";
|
||||
import { Channel } from "../../../types/channels/channel.ts";
|
||||
import { StartThread } from "../../../types/channels/threads/start_thread.ts";
|
||||
import { Errors } from "../../../types/discordeno/errors.ts";
|
||||
import { endpoints } from "../../../util/constants.ts";
|
||||
@@ -18,5 +19,7 @@ export async function startPrivateThread(channelId: bigint, options: StartThread
|
||||
await requireBotChannelPermissions(channel, ["SEND_MESSAGES", "USE_PRIVATE_THREADS"]);
|
||||
}
|
||||
|
||||
return channelToThread(await rest.runMethod("post", endpoints.THREAD_START_PRIVATE(channelId), snakelize(options)));
|
||||
return channelToThread(
|
||||
await rest.runMethod<Channel>("post", endpoints.THREAD_START_PRIVATE(channelId), snakelize(options))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { cacheHandlers } from "../../../cache.ts";
|
||||
import { rest } from "../../../rest/rest.ts";
|
||||
import { Channel } from "../../../types/channels/channel.ts";
|
||||
import { StartThread } from "../../../types/channels/threads/start_thread.ts";
|
||||
import { Errors } from "../../../types/discordeno/errors.ts";
|
||||
import { endpoints } from "../../../util/constants.ts";
|
||||
import { requireBotChannelPermissions } from "../../../util/permissions.ts";
|
||||
import { channelToThread } from "../../../util/transformers/channel_to_thread.ts";
|
||||
import { snakelize } from "../../../util/utils.ts";
|
||||
|
||||
/** Creates a new public thread from an existing message. Returns a thread channel. */
|
||||
export async function startThread(channelId: bigint, options: StartThread & { messageId: bigint }) {
|
||||
export async function startThread(channelId: bigint, messageId: bigint, options: StartThread) {
|
||||
const channel = await cacheHandlers.get("channels", channelId);
|
||||
if (channel) {
|
||||
if (!channel.isGuildTextBasedChannel) {
|
||||
@@ -17,9 +19,7 @@ export async function startThread(channelId: bigint, options: StartThread & { me
|
||||
await requireBotChannelPermissions(channel, ["SEND_MESSAGES", "USE_PUBLIC_THREADS"]);
|
||||
}
|
||||
|
||||
return await rest.runMethod(
|
||||
"post",
|
||||
endpoints.THREAD_START_PUBLIC(channelId, options.messageId),
|
||||
snakelize(options)
|
||||
return channelToThread(
|
||||
await rest.runMethod<Channel>("post", endpoints.THREAD_START_PUBLIC(channelId, messageId), snakelize(options))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { editThread } from "./edit_thread.ts";
|
||||
|
||||
/** Sets a thread channel to be unarchived. */
|
||||
export function unarchiveThread(threadId: bigint) {
|
||||
return editThread(threadId, { archived: false });
|
||||
export async function unarchiveThread(threadId: bigint) {
|
||||
return await editThread(threadId, { archived: false });
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { editThread } from "./edit_thread.ts";
|
||||
|
||||
/** Sets a thread channel to be unlocked. */
|
||||
export function unlockThread(threadId: bigint) {
|
||||
return editThread(threadId, { locked: false });
|
||||
export async function unlockThread(threadId: bigint) {
|
||||
return await editThread(threadId, { locked: false });
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@ import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
import { snakelize } from "../../util/utils.ts";
|
||||
|
||||
/** Ban a user from the guild and optionally delete previous messages sent by the user. Requires the BAN_MEMBERS permission. */
|
||||
export async function ban(guildId: bigint, id: bigint, options: CreateGuildBan) {
|
||||
export async function ban(guildId: bigint, id: bigint, options?: CreateGuildBan) {
|
||||
await requireBotGuildPermissions(guildId, ["BAN_MEMBERS"]);
|
||||
|
||||
return await rest.runMethod<undefined>("put", endpoints.GUILD_BAN(guildId, id), snakelize(options));
|
||||
return await rest.runMethod<undefined>("put", endpoints.GUILD_BAN(guildId, id), snakelize(options ?? {}));
|
||||
}
|
||||
|
||||
// aliases
|
||||
|
||||
@@ -29,11 +29,6 @@ export async function editMessage(channelId: bigint, messageId: bigint, content:
|
||||
validateComponents(content.components);
|
||||
}
|
||||
|
||||
// TODO: v12 remove
|
||||
if (content.embed) {
|
||||
content.embeds = [content.embed, ...(content.embeds || [])];
|
||||
content.embed = undefined;
|
||||
}
|
||||
content.embeds?.splice(10);
|
||||
|
||||
if (content.content && content.content.length > 2000) {
|
||||
|
||||
@@ -34,11 +34,6 @@ export async function sendMessage(channelId: bigint, content: string | CreateMes
|
||||
const requiredPerms: Set<PermissionStrings> = new Set(["SEND_MESSAGES", "VIEW_CHANNEL"]);
|
||||
|
||||
if (content.tts) requiredPerms.add("SEND_TTS_MESSAGES");
|
||||
// TODO: v12 remove
|
||||
if (content.embed) {
|
||||
content.embeds = [content.embed, ...(content.embeds || [])];
|
||||
content.embed = undefined;
|
||||
}
|
||||
if (content.embeds?.length) {
|
||||
requiredPerms.add("EMBED_LINKS");
|
||||
content.embeds?.splice(10);
|
||||
|
||||
@@ -100,6 +100,7 @@ import { editBotProfile } from "./misc/edit_bot_profile.ts";
|
||||
import { editBotStatus } from "./misc/edit_bot_status.ts";
|
||||
import { getGatewayBot } from "./misc/get_gateway_bot.ts";
|
||||
import { getUser } from "./misc/get_user.ts";
|
||||
import { getApplicationInfo } from "./oauth/get_application.ts";
|
||||
import { addRole } from "./roles/add_role.ts";
|
||||
import { createRole } from "./roles/create_role.ts";
|
||||
import { deleteRole } from "./roles/delete_role.ts";
|
||||
@@ -246,6 +247,7 @@ export {
|
||||
getStageInstance,
|
||||
getTemplate,
|
||||
getUser,
|
||||
getApplicationInfo,
|
||||
getVanityURL,
|
||||
getVoiceRegions,
|
||||
getWebhook,
|
||||
|
||||
8
src/helpers/oauth/get_application.ts
Normal file
8
src/helpers/oauth/get_application.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { rest } from "../../rest/rest.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { Application } from "../../types/applications/application.ts";
|
||||
|
||||
/** Get the applications info */
|
||||
export async function getApplicationInfo() {
|
||||
return await rest.runMethod<Omit<Application, "flags">>("get", endpoints.OAUTH2_APPLICATION);
|
||||
}
|
||||
@@ -109,32 +109,36 @@ const baseChannel: Partial<DiscordenoChannel> = {
|
||||
export async function createDiscordenoChannel(data: Channel, guildId?: bigint) {
|
||||
const { lastPinTimestamp, permissionOverwrites = [], ...rest } = data;
|
||||
|
||||
const requiredPropsSize = cache.requiredStructureProperties.channels.size;
|
||||
|
||||
const props: Record<string, PropertyDescriptor> = {};
|
||||
(Object.keys(rest) as (keyof typeof rest)[]).forEach((key) => {
|
||||
for (const key of Object.keys(rest) as (keyof typeof rest)[]) {
|
||||
eventHandlers.debug?.("loop", `Running forEach loop in createDiscordenoChannel function.`);
|
||||
// If empty then support all, otherwise we only allow the ones user added
|
||||
if (requiredPropsSize && !cache.requiredStructureProperties.channels.has(key)) continue;
|
||||
|
||||
props[key] = createNewProp(
|
||||
CHANNEL_SNOWFLAKES.includes(key) ? (rest[key] ? snowflakeToBigint(rest[key] as string) : undefined) : rest[key]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Set the guildId seperately because sometimes guildId is not included
|
||||
props.guildId = createNewProp(snowflakeToBigint(guildId?.toString() || data.guildId || ""));
|
||||
if (!requiredPropsSize || cache.requiredStructureProperties.channels.has("guildId"))
|
||||
props.guildId = createNewProp(snowflakeToBigint(guildId?.toString() || data.guildId || ""));
|
||||
|
||||
const channel: DiscordenoChannel = Object.create(baseChannel, {
|
||||
...props,
|
||||
lastPinTimestamp: createNewProp(lastPinTimestamp ? Date.parse(lastPinTimestamp) : undefined),
|
||||
permissionOverwrites: createNewProp(
|
||||
if (!requiredPropsSize || cache.requiredStructureProperties.channels.has("lastPinTimestamp"))
|
||||
props.lastPinTimestamp = createNewProp(lastPinTimestamp ? Date.parse(lastPinTimestamp) : undefined);
|
||||
if (!requiredPropsSize || cache.requiredStructureProperties.channels.has("permissionOverwrites"))
|
||||
props.permissionOverwrites = createNewProp(
|
||||
permissionOverwrites.map((o) => ({
|
||||
...o,
|
||||
id: snowflakeToBigint(o.id),
|
||||
allow: snowflakeToBigint(o.allow),
|
||||
deny: snowflakeToBigint(o.deny),
|
||||
}))
|
||||
),
|
||||
});
|
||||
);
|
||||
|
||||
return channel;
|
||||
return Object.create(baseChannel, props) as DiscordenoChannel;
|
||||
}
|
||||
|
||||
export interface DiscordenoChannel
|
||||
|
||||
@@ -264,7 +264,11 @@ export async function createDiscordenoGuild(data: Guild, shardId: number) {
|
||||
});
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
await Promise.all(
|
||||
promises.map(async (promise) => {
|
||||
return await promise();
|
||||
})
|
||||
);
|
||||
|
||||
const roles = await Promise.all(
|
||||
(data.roles || []).map((role) =>
|
||||
@@ -283,27 +287,37 @@ export async function createDiscordenoGuild(data: Guild, shardId: number) {
|
||||
);
|
||||
|
||||
const props: Record<string, ReturnType<typeof createNewProp>> = {};
|
||||
(Object.keys(rest) as (keyof typeof rest)[]).forEach((key) => {
|
||||
for (const key of Object.keys(rest) as (keyof typeof rest)[]) {
|
||||
eventHandlers.debug?.("loop", `Running for of loop in createDiscordenoGuild function.`);
|
||||
|
||||
// If its empty default allows all, otherwise only allow those users required.
|
||||
if (cache.requiredStructureProperties.guilds.size && !cache.requiredStructureProperties.guilds.has(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const toggleBits = guildToggles[key as keyof typeof guildToggles];
|
||||
if (toggleBits) {
|
||||
bitfield |= rest[key] ? toggleBits : 0n;
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
props[key] = createNewProp(
|
||||
GUILD_SNOWFLAKES.includes(key) ? (rest[key] ? snowflakeToBigint(rest[key] as string) : undefined) : rest[key]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const hashes = [
|
||||
{ name: "icon", toggle: guildToggles.animatedIcon, value: icon },
|
||||
{ name: "banner", toggle: guildToggles.animatedBanner, value: banner },
|
||||
{ name: "splash", toggle: guildToggles.animatedSplash, value: splash },
|
||||
];
|
||||
] as const;
|
||||
|
||||
for (const hash of hashes) {
|
||||
// If its empty default allows all, otherwise only allow those users required.
|
||||
if (cache.requiredStructureProperties.guilds.size && !cache.requiredStructureProperties.guilds.has(hash.name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const transformed = hash.value ? iconHashToBigInt(hash.value) : undefined;
|
||||
if (transformed) {
|
||||
props[hash.name] = createNewProp(hash.value);
|
||||
@@ -311,20 +325,35 @@ export async function createDiscordenoGuild(data: Guild, shardId: number) {
|
||||
}
|
||||
}
|
||||
|
||||
const guild: DiscordenoGuild = Object.create(baseGuild, {
|
||||
...props,
|
||||
shardId: createNewProp(shardId),
|
||||
roles: createNewProp(new Collection(roles.map((r: DiscordenoRole) => [r.id, r]))),
|
||||
joinedAt: createNewProp(Date.parse(joinedAt)),
|
||||
presences: createNewProp(new Collection(presences.map((p) => [snowflakeToBigint(p.user!.id), p]))),
|
||||
memberCount: createNewProp(memberCount),
|
||||
emojis: createNewProp(new Collection(emojis.map((emoji) => [snowflakeToBigint(emoji.id!), emoji]))),
|
||||
voiceStates: createNewProp(new Collection(voiceStateStructs.map((vs) => [vs.userId, vs]))),
|
||||
bitfield: createNewProp(bitfield),
|
||||
});
|
||||
if (!cache.requiredStructureProperties.guilds.size || cache.requiredStructureProperties.guilds.has("roles")) {
|
||||
props.roles = createNewProp(new Collection(roles.map((r: DiscordenoRole) => [r.id, r])));
|
||||
}
|
||||
if (!cache.requiredStructureProperties.guilds.size || cache.requiredStructureProperties.guilds.has("joinedAt")) {
|
||||
props.joinedAt = createNewProp(Date.parse(joinedAt));
|
||||
}
|
||||
if (!cache.requiredStructureProperties.guilds.size || cache.requiredStructureProperties.guilds.has("presences")) {
|
||||
props.presences = createNewProp(new Collection(presences.map((p) => [snowflakeToBigint(p.user!.id), p])));
|
||||
}
|
||||
if (!cache.requiredStructureProperties.guilds.size || cache.requiredStructureProperties.guilds.has("memberCount")) {
|
||||
props.memberCount = createNewProp(memberCount);
|
||||
}
|
||||
if (!cache.requiredStructureProperties.guilds.size || cache.requiredStructureProperties.guilds.has("emojis")) {
|
||||
props.emojis = createNewProp(new Collection(emojis.map((emoji) => [snowflakeToBigint(emoji.id!), emoji])));
|
||||
}
|
||||
if (!cache.requiredStructureProperties.guilds.size || cache.requiredStructureProperties.guilds.has("voiceStates")) {
|
||||
props.voiceStates = createNewProp(new Collection(voiceStateStructs.map((vs) => [vs.userId, vs])));
|
||||
}
|
||||
// @ts-ignore allow using these props
|
||||
if (!cache.requiredStructureProperties.guilds.size || cache.requiredStructureProperties.guilds.has("shardId")) {
|
||||
props.shardId = createNewProp(shardId);
|
||||
}
|
||||
// @ts-ignore allow using these props
|
||||
if (!cache.requiredStructureProperties.guilds.size || cache.requiredStructureProperties.guilds.has("bitfield")) {
|
||||
props.bitfield = createNewProp(bitfield);
|
||||
}
|
||||
|
||||
const guild: DiscordenoGuild = Object.create(baseGuild, props);
|
||||
await cacheMembers(guild.id, members as GuildMemberWithUser[]);
|
||||
|
||||
return guild;
|
||||
}
|
||||
|
||||
@@ -441,7 +470,7 @@ export interface DiscordenoGuild
|
||||
/** Returns a list of ban objects for the users banned from this guild. Requires the BAN_MEMBERS permission. */
|
||||
bans(): ReturnType<typeof getBans>;
|
||||
/** Ban a user from the guild and optionally delete previous messages sent by the user. Requires the BAN_MEMBERS permission. */
|
||||
ban(memberId: bigint, options: CreateGuildBan): ReturnType<typeof banMember>;
|
||||
ban(memberId: bigint, options?: CreateGuildBan): ReturnType<typeof banMember>;
|
||||
/** Remove the ban for a user. Requires BAN_MEMBERS permission */
|
||||
unban(memberId: bigint): ReturnType<typeof unbanMember>;
|
||||
/** Get all the invites for this guild. Requires MANAGE_GUILD permission */
|
||||
|
||||
@@ -137,39 +137,48 @@ export async function createDiscordenoMember(
|
||||
|
||||
let bitfield = 0n;
|
||||
const props: Record<string, ReturnType<typeof createNewProp>> = {};
|
||||
(Object.keys(user) as (keyof typeof user)[]).forEach((key) => {
|
||||
|
||||
for (const key of Object.keys(user) as (keyof typeof user)[]) {
|
||||
eventHandlers.debug?.("loop", `Running for of for Object.keys(user) loop in DiscordenoMember function.`);
|
||||
|
||||
// @ts-ignore allow user prop args
|
||||
if (cache.requiredStructureProperties.members.size && !cache.requiredStructureProperties.members.has(key)) continue;
|
||||
|
||||
const toggleBits = memberToggles[key as keyof typeof memberToggles];
|
||||
if (toggleBits) {
|
||||
bitfield |= user[key] ? toggleBits : 0n;
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key === "avatar") {
|
||||
const transformed = user[key] ? iconHashToBigInt(user[key] as string) : undefined;
|
||||
if (transformed?.animated) bitfield |= memberToggles.animatedAvatar;
|
||||
props.avatar = createNewProp(transformed?.bigint);
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key === "discriminator") {
|
||||
props.discriminator = createNewProp(Number(user[key]));
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
props[key] = createNewProp(
|
||||
MEMBER_SNOWFLAKES.includes(key) ? (user[key] ? snowflakeToBigint(user[key] as string) : undefined) : user[key]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const member: DiscordenoMember = Object.create(baseMember, {
|
||||
...props,
|
||||
/** The guild related data mapped by guild id */
|
||||
guilds: createNewProp(new Collection<bigint, GuildMember>()),
|
||||
bitfield: createNewProp(bitfield),
|
||||
cachedAt: createNewProp(Date.now()),
|
||||
});
|
||||
/** The guild related data mapped by guild id */
|
||||
// @ts-ignore allow this prop to be required
|
||||
if (!cache.requiredStructureProperties.members.size || cache.requiredStructureProperties.members.has("guilds"))
|
||||
props.guilds = createNewProp(new Collection<bigint, GuildMember>());
|
||||
// @ts-ignore allow this prop to be required
|
||||
if (!cache.requiredStructureProperties.members.size || cache.requiredStructureProperties.members.has("bitfield"))
|
||||
props.bitfield = createNewProp(bitfield);
|
||||
// @ts-ignore allow this prop to be required
|
||||
if (!cache.requiredStructureProperties.members.size || cache.requiredStructureProperties.members.has("cachedAt"))
|
||||
props.cachedAt = createNewProp(Date.now());
|
||||
|
||||
const member: DiscordenoMember = Object.create(baseMember, props);
|
||||
|
||||
const cached = await cacheHandlers.get("members", snowflakeToBigint(user.id));
|
||||
if (cached) {
|
||||
@@ -251,7 +260,7 @@ export interface DiscordenoMember extends Omit<User, "discriminator" | "id" | "a
|
||||
}
|
||||
): ReturnType<typeof editMember>;
|
||||
/** Ban a member in a guild */
|
||||
ban(guildId: bigint, options: CreateGuildBan): ReturnType<typeof banMember>;
|
||||
ban(guildId: bigint, options?: CreateGuildBan): ReturnType<typeof banMember>;
|
||||
/** Add a role to the member */
|
||||
addRole(guildId: bigint, roleId: bigint, reason?: string): ReturnType<typeof addRole>;
|
||||
/** Remove a role from the member */
|
||||
|
||||
@@ -116,16 +116,16 @@ const baseMessage: Partial<DiscordenoMessage> = {
|
||||
async alert(content, timeout = 10, reason = "") {
|
||||
if (this.guildId) {
|
||||
return await sendMessage(this.channelId!, content).then((response) => {
|
||||
response.delete(reason, timeout * 1000).catch(console.error);
|
||||
response?.delete(reason, timeout * 1000).catch(console.error);
|
||||
});
|
||||
}
|
||||
|
||||
return await sendDirectMessage(this.authorId!, content).then((response) => {
|
||||
response.delete(reason, timeout * 1000).catch(console.error);
|
||||
response?.delete(reason, timeout * 1000).catch(console.error);
|
||||
});
|
||||
},
|
||||
async alertReply(content, timeout = 10, reason = "") {
|
||||
return await this.reply!(content).then((response) => response.delete(reason, timeout * 1000).catch(console.error));
|
||||
return await this.reply!(content).then((response) => response?.delete(reason, timeout * 1000).catch(console.error));
|
||||
},
|
||||
removeAllReactions() {
|
||||
return removeAllReactions(this.channelId!, this.id!);
|
||||
@@ -213,29 +213,41 @@ export async function createDiscordenoMessage(data: Message) {
|
||||
let bitfield = 0n;
|
||||
|
||||
const props: Record<string, ReturnType<typeof createNewProp>> = {};
|
||||
(Object.keys(rest) as (keyof typeof rest)[]).forEach((key) => {
|
||||
|
||||
const requiredPropsSize = cache.requiredStructureProperties.messages.size;
|
||||
|
||||
for (const key of Object.keys(rest) as (keyof typeof rest)[]) {
|
||||
eventHandlers.debug?.("loop", `Running for of loop in createDiscordenoMessage function.`);
|
||||
|
||||
// If empty all are allowed, otherwise check if this prop is allowed
|
||||
if (requiredPropsSize && !cache.requiredStructureProperties.messages.has(key)) continue;
|
||||
|
||||
const toggleBits = messageToggles[key as keyof typeof messageToggles];
|
||||
if (toggleBits) {
|
||||
bitfield |= rest[key] ? toggleBits : 0n;
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't add member to props since it would overwrite the message.member getter
|
||||
// thread should not be cached on a message
|
||||
if (["member", "thread"].includes(key)) return;
|
||||
if (["member", "thread"].includes(key)) continue;
|
||||
|
||||
props[key] = createNewProp(
|
||||
MESSAGE_SNOWFLAKES.includes(key) ? (rest[key] ? snowflakeToBigint(rest[key] as string) : undefined) : rest[key]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (rest.thread) await cacheHandlers.set("threads", snowflakeToBigint(data.id), channelToThread(rest.thread));
|
||||
|
||||
props.authorId = createNewProp(snowflakeToBigint(author.id));
|
||||
props.isBot = createNewProp(author.bot || false);
|
||||
props.tag = createNewProp(`${author.username}#${author.discriminator.toString().padStart(4, "0")}`);
|
||||
// @ts-ignore allow this prop
|
||||
if (!requiredPropsSize || cache.requiredStructureProperties.messages.has("authorId"))
|
||||
props.authorId = createNewProp(snowflakeToBigint(author.id));
|
||||
// @ts-ignore allow this prop
|
||||
if (!requiredPropsSize || cache.requiredStructureProperties.messages.has("isBot"))
|
||||
props.isBot = createNewProp(author.bot || false);
|
||||
// @ts-ignore allow this prop
|
||||
if (!requiredPropsSize || cache.requiredStructureProperties.messages.has("tag"))
|
||||
props.tag = createNewProp(`${author.username}#${author.discriminator.toString().padStart(4, "0")}`);
|
||||
|
||||
// Discord doesnt give guild id for getMessage() so this will fill it in
|
||||
const guildIdFinal =
|
||||
@@ -243,13 +255,28 @@ export async function createDiscordenoMessage(data: Message) {
|
||||
(await cacheHandlers.get("channels", snowflakeToBigint(data.channelId)))?.guildId ||
|
||||
0n;
|
||||
|
||||
const message: DiscordenoMessage = Object.create(baseMessage, {
|
||||
...props,
|
||||
content: createNewProp(data.content || ""),
|
||||
guildId: createNewProp(guildIdFinal),
|
||||
mentionedUserIds: createNewProp(mentions.map((m) => snowflakeToBigint(m.id))),
|
||||
mentionedRoleIds: createNewProp(mentionRoles.map((id) => snowflakeToBigint(id))),
|
||||
mentionedChannelIds: createNewProp([
|
||||
if (!requiredPropsSize || cache.requiredStructureProperties.messages.has("content"))
|
||||
props.content = createNewProp(data.content || "");
|
||||
if (!requiredPropsSize || cache.requiredStructureProperties.messages.has("guildId"))
|
||||
props.guildId = createNewProp(guildIdFinal);
|
||||
if (
|
||||
!requiredPropsSize ||
|
||||
// @ts-ignore allow this prop
|
||||
cache.requiredStructureProperties.messages.has("mentionedUserIds")
|
||||
)
|
||||
props.mentionedUserIds = createNewProp(mentions.map((m) => snowflakeToBigint(m.id)));
|
||||
if (
|
||||
!requiredPropsSize ||
|
||||
// @ts-ignore allow this prop
|
||||
cache.requiredStructureProperties.messages.has("mentionedRoleIds")
|
||||
)
|
||||
props.mentionedRoleIds = createNewProp(mentionRoles.map((id) => snowflakeToBigint(id)));
|
||||
if (
|
||||
!requiredPropsSize ||
|
||||
// @ts-ignore allow this prop
|
||||
cache.requiredStructureProperties.messages.has("mentionedChannelIds")
|
||||
)
|
||||
props.mentionedChannelIds = createNewProp([
|
||||
// Keep any ids that discord sends
|
||||
...mentionChannels.map((m) => snowflakeToBigint(m.id)),
|
||||
// Add any other ids that can be validated in a channel mention format
|
||||
@@ -257,10 +284,13 @@ export async function createDiscordenoMessage(data: Message) {
|
||||
// converts the <#123> into 123
|
||||
snowflakeToBigint(text.substring(2, text.length - 1))
|
||||
),
|
||||
]),
|
||||
timestamp: createNewProp(Date.parse(data.timestamp)),
|
||||
editedTimestamp: createNewProp(editedTimestamp ? Date.parse(editedTimestamp) : undefined),
|
||||
messageReference: createNewProp(
|
||||
]);
|
||||
if (!requiredPropsSize || cache.requiredStructureProperties.messages.has("timestamp"))
|
||||
props.timestamp = createNewProp(Date.parse(data.timestamp));
|
||||
if (!requiredPropsSize || cache.requiredStructureProperties.messages.has("editedTimestamp"))
|
||||
props.editedTimestamp = createNewProp(editedTimestamp ? Date.parse(editedTimestamp) : undefined);
|
||||
if (!requiredPropsSize || cache.requiredStructureProperties.messages.has("messageReference"))
|
||||
props.messageReference = createNewProp(
|
||||
messageReference
|
||||
? {
|
||||
messageId: messageReference.messageId ? snowflakeToBigint(messageReference.messageId) : undefined,
|
||||
@@ -268,11 +298,12 @@ export async function createDiscordenoMessage(data: Message) {
|
||||
guildId: messageReference.guildId ? snowflakeToBigint(messageReference.guildId) : undefined,
|
||||
}
|
||||
: undefined
|
||||
),
|
||||
bitfield: createNewProp(bitfield),
|
||||
});
|
||||
);
|
||||
// @ts-ignore allow this prop
|
||||
if (!requiredPropsSize || cache.requiredStructureProperties.messages.has("bitfield"))
|
||||
props.bitfield = createNewProp(bitfield);
|
||||
|
||||
return message;
|
||||
return Object.create(baseMessage, props) as DiscordenoMessage;
|
||||
}
|
||||
|
||||
export interface DiscordenoMessage
|
||||
|
||||
@@ -115,30 +115,36 @@ export async function createDiscordenoRole(
|
||||
let bitfield = 0n;
|
||||
|
||||
const props: Record<string, ReturnType<typeof createNewProp>> = {};
|
||||
(Object.keys(rest) as (keyof typeof rest)[]).forEach((key) => {
|
||||
for (const key of Object.keys(rest) as (keyof typeof rest)[]) {
|
||||
eventHandlers.debug?.("loop", `Running for of loop in createDiscordenoRole function.`);
|
||||
|
||||
const toggleBits = roleToggles[key as keyof typeof roleToggles];
|
||||
if (toggleBits) {
|
||||
bitfield |= rest[key] ? toggleBits : 0n;
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
props[key] = createNewProp(
|
||||
ROLE_SNOWFLAKES.includes(key) ? (rest[key] ? snowflakeToBigint(rest[key] as string) : undefined) : rest[key]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const role: DiscordenoRole = Object.create(baseRole, {
|
||||
...props,
|
||||
permissions: createNewProp(BigInt(rest.permissions)),
|
||||
botId: createNewProp(tags.botId ? snowflakeToBigint(tags.botId) : undefined),
|
||||
isNitroBoostRole: createNewProp("premiumSubscriber" in tags),
|
||||
integrationId: createNewProp(tags.integrationId ? snowflakeToBigint(tags.integrationId) : undefined),
|
||||
bitfield: createNewProp(bitfield),
|
||||
});
|
||||
if (!cache.requiredStructureProperties.roles.size || cache.requiredStructureProperties.roles.has("permissions"))
|
||||
props.permissions = createNewProp(BigInt(rest.permissions));
|
||||
// @ts-ignore allow this prop
|
||||
if (!cache.requiredStructureProperties.roles.size || cache.requiredStructureProperties.roles.has("botId"))
|
||||
props.botId = createNewProp(tags.botId ? snowflakeToBigint(tags.botId) : undefined);
|
||||
// @ts-ignore allow this prop
|
||||
if (!cache.requiredStructureProperties.roles.size || cache.requiredStructureProperties.roles.has("isNitroBoostRole"))
|
||||
props.isNitroBoostRole = createNewProp("premiumSubscriber" in tags);
|
||||
// @ts-ignore allow this prop
|
||||
if (!cache.requiredStructureProperties.roles.size || cache.requiredStructureProperties.roles.has("integrationId"))
|
||||
props.integrationId = createNewProp(tags.integrationId ? snowflakeToBigint(tags.integrationId) : undefined);
|
||||
// @ts-ignore allow this prop
|
||||
if (!cache.requiredStructureProperties.roles.size || cache.requiredStructureProperties.roles.has("bitfield"))
|
||||
props.bitfield = createNewProp(bitfield);
|
||||
|
||||
return role;
|
||||
return Object.create(baseRole, props) as DiscordenoRole;
|
||||
}
|
||||
|
||||
export interface DiscordenoRole extends Omit<Role, "tags" | "id" | "permissions"> {
|
||||
|
||||
@@ -81,16 +81,20 @@ export async function createDiscordenoVoiceState(guildId: bigint, data: VoiceSta
|
||||
let bitfield = 0n;
|
||||
|
||||
const props: Record<string, ReturnType<typeof createNewProp>> = {};
|
||||
(Object.keys(data) as (keyof typeof data)[]).forEach((key) => {
|
||||
for (const key of Object.keys(data) as (keyof typeof data)[]) {
|
||||
eventHandlers.debug?.("loop", `Running for of loop in createDiscordenoVoiceState function.`);
|
||||
|
||||
// if is empty allow all, otherwise check if prop is required
|
||||
if (cache.requiredStructureProperties.voiceStates.size && !cache.requiredStructureProperties.voiceStates.has(key))
|
||||
continue;
|
||||
|
||||
// We don't need to cache member twice. It will be in cache.members
|
||||
if (key === "member") return;
|
||||
if (key === "member") continue;
|
||||
|
||||
const toggleBits = voiceStateToggles[key as keyof typeof voiceStateToggles];
|
||||
if (toggleBits) {
|
||||
bitfield |= data[key] ? toggleBits : 0n;
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
props[key] = createNewProp(
|
||||
@@ -100,15 +104,21 @@ export async function createDiscordenoVoiceState(guildId: bigint, data: VoiceSta
|
||||
: undefined
|
||||
: data[key]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const voiceState: DiscordenoVoiceState = Object.create(baseRole, {
|
||||
...props,
|
||||
guildId: createNewProp(guildId),
|
||||
bitfield: createNewProp(bitfield),
|
||||
});
|
||||
if (
|
||||
!cache.requiredStructureProperties.voiceStates.size ||
|
||||
cache.requiredStructureProperties.voiceStates.has("guildId")
|
||||
)
|
||||
props.guildId = createNewProp(guildId);
|
||||
if (
|
||||
!cache.requiredStructureProperties.voiceStates.size ||
|
||||
// @ts-ignore allow this prop
|
||||
cache.requiredStructureProperties.voiceStates.has("bitfield")
|
||||
)
|
||||
props.bitfield = createNewProp(bitfield);
|
||||
|
||||
return voiceState;
|
||||
return Object.create(baseRole, props) as DiscordenoVoiceState;
|
||||
}
|
||||
|
||||
export interface DiscordenoVoiceState extends Omit<VoiceState, "channelId" | "guildId" | "userId" | "member"> {
|
||||
|
||||
@@ -33,6 +33,7 @@ export enum DiscordJsonErrorCodes {
|
||||
UnknownInteraction = 10062,
|
||||
UnknownApplicationCommand = 10063,
|
||||
UnknownApplicationCommandPermissions = 10066,
|
||||
UnknownGuildMemberVerificationForm = 10068,
|
||||
BotsCannotUseThisEndpoint = 20001,
|
||||
OnlyBotsCanUseThisEndpoint,
|
||||
ExplicitContentCannotBeSentToTheDesiredRecipient = 20009,
|
||||
@@ -42,6 +43,7 @@ export enum DiscordJsonErrorCodes {
|
||||
ThisMessageCannotBeEditedDueToAnnouncementRateLimits = 20022,
|
||||
TheChannelYouAreWritingHasHitTheWriteRateLimit = 20028,
|
||||
YourStageTopicContainsWordsThatAreNotAllowedForPublicStages = 20031,
|
||||
GuildPremiumSubscriptionLevelTooLow = 20035,
|
||||
MaximumNumberOfGuildsReached = 30001,
|
||||
MaximumNumberOfFriendsReached,
|
||||
MaximumNumberOfPinsReachedForTheChannel,
|
||||
|
||||
@@ -4,9 +4,9 @@ import { ApplicationCommandInteractionDataResolved } from "./application_command
|
||||
/** https://discord.com/developers/docs/interactions/slash-commands#interaction-applicationcommandinteractiondata */
|
||||
export interface ApplicationCommandInteractionData {
|
||||
/** The Id of the invoked command */
|
||||
id?: string;
|
||||
id: string;
|
||||
/** The name of the invoked command */
|
||||
name?: string;
|
||||
name: string;
|
||||
/** Converted users + roles + channels */
|
||||
resolved?: ApplicationCommandInteractionDataResolved;
|
||||
/** The params + values from the user */
|
||||
|
||||
@@ -10,11 +10,6 @@ export interface CreateMessage {
|
||||
content?: string;
|
||||
/** true if this is a TTS message */
|
||||
tts?: boolean;
|
||||
// TODO: v12 remove
|
||||
/** Embedded `rich` content
|
||||
* @deprecated will be removed in Discordeno v12 use embeds
|
||||
*/
|
||||
embed?: Embed;
|
||||
/** Embedded `rich` content (up to 6000 characters) */
|
||||
embeds?: Embed[];
|
||||
/** Allowed mentions for the message */
|
||||
|
||||
@@ -8,11 +8,6 @@ import { MessageComponents } from "./components/message_components.ts";
|
||||
export interface EditMessage {
|
||||
/** The new message contents (up to 2000 characters) */
|
||||
content?: string | null;
|
||||
// TODO: v12 remove
|
||||
/** Embedded `rich` content
|
||||
* @deprecated will be removed in Discordeno v12 use embeds
|
||||
*/
|
||||
embed?: Embed | null;
|
||||
/** Embedded `rich` content (up to 6000 characters) */
|
||||
embeds?: Embed[] | null;
|
||||
/** Edit the flags of the message (only `SUPRESS_EMBEDS` can currently be set/unset) */
|
||||
|
||||
@@ -13,6 +13,7 @@ import { MessageReference } from "./message_reference.ts";
|
||||
import { MessageSticker } from "./message_sticker.ts";
|
||||
import { DiscordMessageTypes } from "./message_types.ts";
|
||||
import { Reaction } from "./reaction.ts";
|
||||
import { MessageStickerItem } from "./message_sticker_item.ts";
|
||||
|
||||
/** https://discord.com/developers/docs/resources/channel#message-object */
|
||||
export interface Message {
|
||||
@@ -93,5 +94,7 @@ export interface Message {
|
||||
/** The thread that was started from this message, includes thread member object */
|
||||
thread?: Omit<Channel, "member"> & { member: ThreadMember };
|
||||
/** The components related to this message */
|
||||
components: MessageComponents;
|
||||
components?: MessageComponents;
|
||||
/** Sent if the message contains stickers */
|
||||
stickerItems?: MessageStickerItem[];
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ export enum DiscordMessageFlags {
|
||||
/** This message originated from a message in another channel (via Channel Following) */
|
||||
IsCrosspost = 1 << 1,
|
||||
/** Do not include any embeds when serializing this message */
|
||||
SuppressEmbeeds = 1 << 2,
|
||||
SuppressEmbeds = 1 << 2,
|
||||
/** The source message for this crosspost has been deleted (via Channel Following) */
|
||||
SourceMessageDeleted = 1 << 3,
|
||||
/** This message came from the urgent message system */
|
||||
|
||||
10
src/types/messages/message_sticker_item.ts
Normal file
10
src/types/messages/message_sticker_item.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { DiscordMessageStickerFormatTypes } from "./message_sticker_format_types.ts";
|
||||
|
||||
export interface MessageStickerItem {
|
||||
/** Id of the sticker */
|
||||
id: string;
|
||||
/** Name of the sticker */
|
||||
name: string;
|
||||
/** Type of sticker format */
|
||||
formatType: DiscordMessageStickerFormatTypes;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { cache } from "../../cache.ts";
|
||||
import { Channel } from "../../types/channels/channel.ts";
|
||||
import { DiscordChannelTypes } from "../../types/channels/channel_types.ts";
|
||||
import { ThreadMemberModified } from "../../types/channels/threads/thread_member.ts";
|
||||
@@ -25,6 +26,9 @@ const baseThread: Partial<DiscordenoThread> = {
|
||||
get isPublic() {
|
||||
return !this.isPrivate;
|
||||
},
|
||||
get guildId() {
|
||||
return cache.channels.get(this.parentId!)!.guildId;
|
||||
},
|
||||
toJSON() {
|
||||
return {
|
||||
id: this.id?.toString(),
|
||||
@@ -98,6 +102,7 @@ export interface DiscordenoThread {
|
||||
isPrivate: boolean;
|
||||
isPublic: boolean;
|
||||
botIsMember: boolean;
|
||||
guildId: bigint;
|
||||
members: Collection<bigint, Omit<ThreadMemberModified, "id">>;
|
||||
toJSON(): Thread;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export * from "./channel_to_thread.ts";
|
||||
export * from "./thread_member_modified.ts";
|
||||
export * from "./thread_members_update_modified.ts"
|
||||
export * from "./thread_members_update_modified.ts";
|
||||
|
||||
Reference in New Issue
Block a user