mirror of
https://github.com/discordeno/discordeno.git
synced 2026-06-16 11:28:15 +00:00
making it testable
This commit is contained in:
Vendored
+1
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"deno.enable": true,
|
||||
"deno.lint": false,
|
||||
"deno.unstable": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
|
||||
@@ -3,7 +3,7 @@ export * from "./src/cache.ts";
|
||||
export * from "./src/handlers/mod.ts";
|
||||
export * from "./src/helpers/mod.ts";
|
||||
export * from "./src/rest/mod.ts";
|
||||
export * from "./src/structures/mod.ts";
|
||||
export * from "./src/transformers/mod.ts";
|
||||
export * from "./src/types/mod.ts";
|
||||
export * from "./src/util/mod.ts";
|
||||
export * from "./src/ws/mod.ts";
|
||||
|
||||
+25
-26
@@ -296,7 +296,7 @@ import { DiscordenoEmoji, transformEmoji } from "./transformers/emoji.ts";
|
||||
import { transformActivity } from "./transformers/activity.ts";
|
||||
import { DiscordenoPresence, transformPresence } from "./transformers/presence.ts";
|
||||
|
||||
export async function createBot(options: CreateBotOptions) {
|
||||
export function createBot(options: CreateBotOptions) {
|
||||
return {
|
||||
id: options.botId,
|
||||
applicationId: options.applicationId || options.botId,
|
||||
@@ -430,13 +430,6 @@ export async function createBot(options: CreateBotOptions) {
|
||||
};
|
||||
}
|
||||
|
||||
const bot = await createBot({
|
||||
token: "",
|
||||
botId: 0n,
|
||||
events: createEventHandlers({}),
|
||||
intents: [],
|
||||
});
|
||||
|
||||
export function createEventHandlers(events: Partial<EventHandlers>): EventHandlers {
|
||||
function ignore() {}
|
||||
|
||||
@@ -543,14 +536,27 @@ export function createRestManager(options: CreateRestManagerOptions) {
|
||||
export async function startBot(bot: Bot) {
|
||||
// SETUP
|
||||
bot.utils = createUtils({});
|
||||
bot.transformers = createTransformers(bot.transformers);
|
||||
bot.helpers = createHelpers(bot.helpers);
|
||||
bot.transformers = createTransformers(bot.transformers || {});
|
||||
bot.helpers = createHelpers(bot.helpers || {});
|
||||
|
||||
// START REST
|
||||
bot.rest = createRestManager({ token: bot.token });
|
||||
|
||||
// START WS
|
||||
bot.gateway = createGatewayManager({});
|
||||
bot.gateway = createGatewayManager({
|
||||
handleDiscordPayload:
|
||||
// bot.handleDiscordPayload ||
|
||||
async function (_, data: DiscordGatewayPayload, shardId: number) {
|
||||
// TRIGGER RAW EVENT
|
||||
bot.events.raw(bot as Bot, data, shardId);
|
||||
|
||||
if (!data.t) return;
|
||||
|
||||
// RUN DISPATCH CHECK
|
||||
await bot.events.dispatchRequirements(bot as Bot, data, shardId);
|
||||
bot.handlers[data.t as GatewayDispatchEventNames]?.(bot as Bot, data, shardId);
|
||||
},
|
||||
});
|
||||
|
||||
if (!bot.botGatewayData) bot.botGatewayData = await bot.helpers.getGatewayBot(bot);
|
||||
}
|
||||
@@ -612,7 +618,9 @@ export interface HelperUtils {
|
||||
validateComponents: typeof validateComponents;
|
||||
}
|
||||
|
||||
export function createGatewayManager(options: Partial<GatewayManager>): GatewayManager {
|
||||
export function createGatewayManager(
|
||||
options: Partial<GatewayManager> & Pick<GatewayManager, "handleDiscordPayload">
|
||||
): GatewayManager {
|
||||
return {
|
||||
cache: {
|
||||
guildIds: new Set(),
|
||||
@@ -661,18 +669,7 @@ export function createGatewayManager(options: Partial<GatewayManager>): GatewayM
|
||||
closeWS,
|
||||
sendShardMessage,
|
||||
resume,
|
||||
handleDiscordPayload:
|
||||
options.handleDiscordPayload ||
|
||||
async function (_, data: DiscordGatewayPayload, shardId: number) {
|
||||
// TRIGGER RAW EVENT
|
||||
bot.events.raw(bot as Bot, data, shardId);
|
||||
|
||||
if (!data.t) return;
|
||||
|
||||
// RUN DISPATCH CHECK
|
||||
await bot.events.dispatchRequirements(bot as Bot, data, shardId);
|
||||
bot.handlers[data.t as GatewayDispatchEventNames]?.(bot as Bot, data, shardId);
|
||||
},
|
||||
handleDiscordPayload: options.handleDiscordPayload,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -693,7 +690,7 @@ export interface CreateBotOptions {
|
||||
|
||||
export type UnPromise<T extends Promise<unknown>> = T extends Promise<infer K> ? K : never;
|
||||
|
||||
export type CreatedBot = UnPromise<ReturnType<typeof createBot>>;
|
||||
export type CreatedBot = ReturnType<typeof createBot>;
|
||||
|
||||
export type Bot = CreatedBot & {
|
||||
utils: HelperUtils;
|
||||
@@ -1369,7 +1366,9 @@ export interface BotGatewayHandlerOptions {
|
||||
INTEGRATION_DELETE: typeof handleIntegrationDelete;
|
||||
}
|
||||
|
||||
export function createBotGatewayHandlers(options: Partial<BotGatewayHandlerOptions>): Record<GatewayDispatchEventNames | "GUILD_LOADED_DD", (bot: Bot, data: GatewayPayload, shardId: number) => any> {
|
||||
export function createBotGatewayHandlers(
|
||||
options: Partial<BotGatewayHandlerOptions>
|
||||
): Record<GatewayDispatchEventNames | "GUILD_LOADED_DD", (bot: Bot, data: GatewayPayload, shardId: number) => any> {
|
||||
return {
|
||||
// misc
|
||||
READY: options.READY ?? handleReady,
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
// import { eventHandlers } from "../../bot.ts";
|
||||
// import { cacheHandlers } from "../../cache.ts";
|
||||
import { Channel } from "../../types/channels/channel.ts";
|
||||
import { DiscordGatewayPayload } from "../../types/gateway/gateway_payload.ts";
|
||||
import { snowflakeToBigint } from "../../util/bigint.ts";
|
||||
|
||||
export async function handleThreadDelete(data: DiscordGatewayPayload) {
|
||||
const payload = data.d as Channel;
|
||||
// const payload = data.d as Channel;
|
||||
|
||||
const cachedChannel = await cacheHandlers.get("threads", snowflakeToBigint(payload.id));
|
||||
if (!cachedChannel) return;
|
||||
// const cachedChannel = await cacheHandlers.get("threads", snowflakeToBigint(payload.id));
|
||||
// if (!cachedChannel) return;
|
||||
|
||||
await cacheHandlers.delete("threads", snowflakeToBigint(payload.id));
|
||||
await cacheHandlers.forEach("DELETE_MESSAGES_FROM_CHANNEL", { channelId: snowflakeToBigint(payload.id) });
|
||||
// await cacheHandlers.delete("threads", snowflakeToBigint(payload.id));
|
||||
// await cacheHandlers.forEach("DELETE_MESSAGES_FROM_CHANNEL", { channelId: snowflakeToBigint(payload.id) });
|
||||
|
||||
eventHandlers.threadDelete?.(cachedChannel);
|
||||
// eventHandlers.threadDelete?.(cachedChannel);
|
||||
}
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
// import { eventHandlers } from "../../bot.ts";
|
||||
// import { cacheHandlers } from "../../cache.ts";
|
||||
import { ThreadListSync } from "../../types/channels/threads/thread_list_sync.ts";
|
||||
import { DiscordGatewayPayload } from "../../types/gateway/gateway_payload.ts";
|
||||
import { snowflakeToBigint } from "../../util/bigint.ts";
|
||||
import { channelToThread } from "../../util/transformers/channel_to_thread.ts";
|
||||
// import { channelToThread } from "../../util/transformers/channel_to_thread.ts";
|
||||
import { Collection } from "../../util/collection.ts";
|
||||
import { threadMemberModified } from "../../util/transformers/thread_member_modified.ts";
|
||||
// import { threadMemberModified } from "../../util/transformers/thread_member_modified.ts";
|
||||
|
||||
export async function handleThreadListSync(data: DiscordGatewayPayload) {
|
||||
const payload = data.d as ThreadListSync;
|
||||
// const payload = data.d as ThreadListSync;
|
||||
|
||||
const threads = await Promise.all(
|
||||
payload.threads.map(async (thread) => {
|
||||
const threadData = channelToThread(thread);
|
||||
await cacheHandlers.set("threads", threadData.id, threadData);
|
||||
// const threads = await Promise.all(
|
||||
// payload.threads.map(async (thread) => {
|
||||
// const threadData = channelToThread(thread);
|
||||
// await cacheHandlers.set("threads", threadData.id, threadData);
|
||||
|
||||
return threadData;
|
||||
})
|
||||
);
|
||||
// return threadData;
|
||||
// })
|
||||
// );
|
||||
|
||||
eventHandlers.threadListSync?.(
|
||||
new Collection(threads.map((t) => [t.id, t])),
|
||||
payload.members.map((member) => threadMemberModified(member)),
|
||||
snowflakeToBigint(payload.guildId)
|
||||
);
|
||||
// eventHandlers.threadListSync?.(
|
||||
// new Collection(threads.map((t) => [t.id, t])),
|
||||
// payload.members.map((member) => threadMemberModified(member)),
|
||||
// snowflakeToBigint(payload.guildId)
|
||||
// );
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
// import { eventHandlers } from "../../bot.ts";
|
||||
// import { cacheHandlers } from "../../cache.ts";
|
||||
import { ThreadMembersUpdate } from "../../types/channels/threads/thread_members_update.ts";
|
||||
import { DiscordGatewayPayload } from "../../types/gateway/gateway_payload.ts";
|
||||
import { snowflakeToBigint } from "../../util/bigint.ts";
|
||||
import { threadMembersUpdateModified } from "../../util/transformers/thread_members_update_modified.ts";
|
||||
// import { threadMembersUpdateModified } from "../../util/transformers/thread_members_update_modified.ts";
|
||||
|
||||
export async function handleThreadMembersUpdate(data: DiscordGatewayPayload) {
|
||||
const payload = data.d as ThreadMembersUpdate;
|
||||
const thread = await cacheHandlers.get("threads", snowflakeToBigint(payload.id));
|
||||
if (!thread) return;
|
||||
// const payload = data.d as ThreadMembersUpdate;
|
||||
// const thread = await cacheHandlers.get("threads", snowflakeToBigint(payload.id));
|
||||
// if (!thread) return;
|
||||
|
||||
thread.memberCount = payload.memberCount;
|
||||
await cacheHandlers.set("threads", thread.id, thread);
|
||||
// thread.memberCount = payload.memberCount;
|
||||
// await cacheHandlers.set("threads", thread.id, thread);
|
||||
|
||||
eventHandlers.threadMembersUpdate?.(threadMembersUpdateModified(payload));
|
||||
// eventHandlers.threadMembersUpdate?.(threadMembersUpdateModified(payload));
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
// import { eventHandlers } from "../../bot.ts";
|
||||
// import { cacheHandlers } from "../../cache.ts";
|
||||
import { ThreadMember } from "../../types/channels/threads/thread_member.ts";
|
||||
import { DiscordGatewayPayload } from "../../types/gateway/gateway_payload.ts";
|
||||
import { snowflakeToBigint } from "../../util/bigint.ts";
|
||||
|
||||
export async function handleThreadMemberUpdate(data: DiscordGatewayPayload) {
|
||||
const payload = data.d as ThreadMember;
|
||||
// The id field is omitted from the thread member dispatched within the GUILD_CREATE gateway event.
|
||||
const thread = await cacheHandlers.get("threads", snowflakeToBigint(payload.id!));
|
||||
if (!thread) return;
|
||||
// const payload = data.d as ThreadMember;
|
||||
// // The id field is omitted from the thread member dispatched within the GUILD_CREATE gateway event.
|
||||
// const thread = await cacheHandlers.get("threads", snowflakeToBigint(payload.id!));
|
||||
// if (!thread) return;
|
||||
|
||||
thread.botIsMember = true;
|
||||
await cacheHandlers.set("threads", thread.id, thread);
|
||||
// thread.botIsMember = true;
|
||||
// await cacheHandlers.set("threads", thread.id, thread);
|
||||
|
||||
const member = {
|
||||
...payload,
|
||||
id: snowflakeToBigint(payload.id!),
|
||||
userId: snowflakeToBigint(payload.userId!),
|
||||
joinTimestamp: Date.parse(payload.joinTimestamp),
|
||||
};
|
||||
// const member = {
|
||||
// ...payload,
|
||||
// id: snowflakeToBigint(payload.id!),
|
||||
// userId: snowflakeToBigint(payload.userId!),
|
||||
// joinTimestamp: Date.parse(payload.joinTimestamp),
|
||||
// };
|
||||
|
||||
eventHandlers.threadMemberUpdate?.(member, thread);
|
||||
// eventHandlers.threadMemberUpdate?.(member, thread);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
// import { eventHandlers } from "../../bot.ts";
|
||||
// import { cacheHandlers } from "../../cache.ts";
|
||||
import { Channel } from "../../types/channels/channel.ts";
|
||||
import { DiscordGatewayPayload } from "../../types/gateway/gateway_payload.ts";
|
||||
import { snowflakeToBigint } from "../../util/bigint.ts";
|
||||
import { channelToThread } from "../../util/transformers/channel_to_thread.ts";
|
||||
// import { channelToThread } from "../../util/transformers/channel_to_thread.ts";
|
||||
|
||||
export async function handleThreadUpdate(data: DiscordGatewayPayload) {
|
||||
const payload = data.d as Channel;
|
||||
const oldThread = await cacheHandlers.get("threads", snowflakeToBigint(payload.id));
|
||||
if (!oldThread) return;
|
||||
// const payload = data.d as Channel;
|
||||
// const oldThread = await cacheHandlers.get("threads", snowflakeToBigint(payload.id));
|
||||
// if (!oldThread) return;
|
||||
|
||||
const thread = channelToThread(payload);
|
||||
await cacheHandlers.set("threads", thread.id, thread);
|
||||
// const thread = channelToThread(payload);
|
||||
// await cacheHandlers.set("threads", thread.id, thread);
|
||||
|
||||
eventHandlers.threadUpdate?.(thread, oldThread);
|
||||
// eventHandlers.threadUpdate?.(thread, oldThread);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ModifyThread } from "../../../types/channels/threads/modify_thread.ts";
|
||||
import type { Bot } from "../../../bot.ts";
|
||||
import { channelToThread } from "../../../util/transformers/channel_to_thread.ts";
|
||||
// import { channelToThread } from "../../../util/transformers/channel_to_thread.ts";
|
||||
|
||||
/** Update a thread's settings. Requires the `MANAGE_CHANNELS` permission for the guild. */
|
||||
export async function editThread(bot: Bot, threadId: bigint, options: ModifyThread, reason?: string) {
|
||||
@@ -8,14 +8,14 @@ export async function editThread(bot: Bot, threadId: bigint, options: ModifyThre
|
||||
|
||||
// TODO: permission checking
|
||||
|
||||
const result = await bot.rest.runMethod(bot.rest, "patch", bot.constants.endpoints.CHANNEL_BASE(threadId), {
|
||||
name: options.name,
|
||||
archived: options.archived,
|
||||
auto_archive_duration: options.autoArchiveDuration,
|
||||
locked: options.locked,
|
||||
rate_limit_per_user: options.rateLimitPerUser,
|
||||
reason,
|
||||
});
|
||||
// const result = await bot.rest.runMethod(bot.rest, "patch", bot.constants.endpoints.CHANNEL_BASE(threadId), {
|
||||
// name: options.name,
|
||||
// archived: options.archived,
|
||||
// auto_archive_duration: options.autoArchiveDuration,
|
||||
// locked: options.locked,
|
||||
// rate_limit_per_user: options.rateLimitPerUser,
|
||||
// reason,
|
||||
// });
|
||||
|
||||
return channelToThread(result);
|
||||
// return channelToThread(result);
|
||||
}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import type { Bot } from "../../../bot.ts";
|
||||
import type { ListActiveThreads } from "../../../types/channels/threads/list_active_threads.ts";
|
||||
import { Collection } from "../../../util/collection.ts";
|
||||
import { channelToThread } from "../../../util/transformers/channel_to_thread.ts";
|
||||
// import { channelToThread } from "../../../util/transformers/channel_to_thread.ts";
|
||||
|
||||
/** Returns all active threads in the channel, including public and private threads. Threads are ordered by their id, in descending order. Requires the VIEW_CHANNEL permission. */
|
||||
export async function getActiveThreads(bot: Bot, channelId: bigint) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["VIEW_CHANNEL"]);
|
||||
// await bot.utils.requireBotChannelPermissions(bot, channelId, ["VIEW_CHANNEL"]);
|
||||
|
||||
// TODO: pagination
|
||||
const result = (await bot.rest.runMethod(
|
||||
bot.rest,
|
||||
"get",
|
||||
bot.constants.endpoints.THREAD_ACTIVE(channelId)
|
||||
)) as ListActiveThreads;
|
||||
// // TODO: pagination
|
||||
// const result = (await bot.rest.runMethod(
|
||||
// bot.rest,
|
||||
// "get",
|
||||
// bot.constants.endpoints.THREAD_ACTIVE(channelId)
|
||||
// )) as ListActiveThreads;
|
||||
|
||||
const threads = new Collection(
|
||||
result.threads.map((t) => {
|
||||
const ddThread = channelToThread(t);
|
||||
return [ddThread.id, ddThread];
|
||||
})
|
||||
);
|
||||
// const threads = new Collection(
|
||||
// result.threads.map((t) => {
|
||||
// const ddThread = channelToThread(t);
|
||||
// return [ddThread.id, ddThread];
|
||||
// })
|
||||
// );
|
||||
|
||||
for (const member of result.members) {
|
||||
const thread = threads.get(bot.transformers.snowflake(member.id!));
|
||||
thread?.members.set(bot.transformers.snowflake(member.userId!), {
|
||||
userId: bot.transformers.snowflake(member.userId!),
|
||||
flags: member.flags,
|
||||
joinTimestamp: Date.parse(member.joinTimestamp),
|
||||
});
|
||||
}
|
||||
|
||||
return threads;
|
||||
// for (const member of result.members) {
|
||||
// const thread = threads.get(bot.transformers.snowflake(member.id!));
|
||||
// thread?.members.set(bot.transformers.snowflake(member.userId!), {
|
||||
// userId: bot.transformers.snowflake(member.userId!),
|
||||
// flags: member.flags,
|
||||
// joinTimestamp: Date.parse(member.joinTimestamp),
|
||||
// });
|
||||
// }
|
||||
|
||||
// return threads;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ListPublicArchivedThreads } from "../../../types/channels/threads/list_
|
||||
import { PermissionStrings } from "../../../types/permissions/permission_strings.ts";
|
||||
import { Collection } from "../../../util/collection.ts";
|
||||
import type { Bot } from "../../../bot.ts";
|
||||
import { channelToThread } from "../../../util/transformers/channel_to_thread.ts";
|
||||
// import { channelToThread } from "../../../util/transformers/channel_to_thread.ts";
|
||||
|
||||
/** Get the archived threads for this channel, defaults to public */
|
||||
export async function getArchivedThreads(
|
||||
@@ -13,45 +13,45 @@ export async function getArchivedThreads(
|
||||
type?: "public" | "private" | "privateJoinedThreads";
|
||||
}
|
||||
) {
|
||||
const permissions = new Set<PermissionStrings>(["READ_MESSAGE_HISTORY"]);
|
||||
if (options?.type === "private") permissions.add("MANAGE_THREADS");
|
||||
// const permissions = new Set<PermissionStrings>(["READ_MESSAGE_HISTORY"]);
|
||||
// if (options?.type === "private") permissions.add("MANAGE_THREADS");
|
||||
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, [...permissions]);
|
||||
// await bot.utils.requireBotChannelPermissions(bot, channelId, [...permissions]);
|
||||
|
||||
// TODO: pagination
|
||||
// // TODO: pagination
|
||||
|
||||
const result = (await bot.rest.runMethod(
|
||||
bot.rest,
|
||||
"get",
|
||||
options?.type === "privateJoinedThreads"
|
||||
? bot.constants.endpoints.THREAD_ARCHIVED_PRIVATE_JOINED(channelId)
|
||||
: options?.type === "private"
|
||||
? bot.constants.endpoints.THREAD_ARCHIVED_PRIVATE(channelId)
|
||||
: bot.constants.endpoints.THREAD_ARCHIVED_PUBLIC(channelId),
|
||||
options
|
||||
? {
|
||||
before: options.before,
|
||||
limit: options.limit,
|
||||
type: options.type,
|
||||
}
|
||||
: {}
|
||||
)) as ListActiveThreads;
|
||||
|
||||
const threads = new Collection(
|
||||
result.threads.map((t) => {
|
||||
const ddThread = channelToThread(t);
|
||||
return [ddThread.id, ddThread];
|
||||
})
|
||||
);
|
||||
|
||||
for (const member of result.members) {
|
||||
const thread = threads.get(bot.transformers.snowflake(member.id!));
|
||||
thread?.members.set(bot.transformers.snowflake(member.userId!), {
|
||||
userId: bot.transformers.snowflake(member.userId!),
|
||||
flags: member.flags,
|
||||
joinTimestamp: Date.parse(member.joinTimestamp),
|
||||
});
|
||||
}
|
||||
|
||||
return threads;
|
||||
// const result = (await bot.rest.runMethod(
|
||||
// bot.rest,
|
||||
// "get",
|
||||
// options?.type === "privateJoinedThreads"
|
||||
// ? bot.constants.endpoints.THREAD_ARCHIVED_PRIVATE_JOINED(channelId)
|
||||
// : options?.type === "private"
|
||||
// ? bot.constants.endpoints.THREAD_ARCHIVED_PRIVATE(channelId)
|
||||
// : bot.constants.endpoints.THREAD_ARCHIVED_PUBLIC(channelId),
|
||||
// options
|
||||
// ? {
|
||||
// before: options.before,
|
||||
// limit: options.limit,
|
||||
// type: options.type,
|
||||
// }
|
||||
// : {}
|
||||
// )) as ListActiveThreads;
|
||||
|
||||
// const threads = new Collection(
|
||||
// result.threads.map((t) => {
|
||||
// const ddThread = channelToThread(t);
|
||||
// return [ddThread.id, ddThread];
|
||||
// })
|
||||
// );
|
||||
|
||||
// for (const member of result.members) {
|
||||
// const thread = threads.get(bot.transformers.snowflake(member.id!));
|
||||
// thread?.members.set(bot.transformers.snowflake(member.userId!), {
|
||||
// userId: bot.transformers.snowflake(member.userId!),
|
||||
// flags: member.flags,
|
||||
// joinTimestamp: Date.parse(member.joinTimestamp),
|
||||
// });
|
||||
// }
|
||||
|
||||
// return threads;
|
||||
}
|
||||
|
||||
@@ -2,31 +2,32 @@ import type { Bot } from "../../../bot.ts";
|
||||
import { ThreadMember } from "../../../types/channels/threads/thread_member.ts";
|
||||
import { DiscordGatewayIntents } from "../../../types/gateway/gateway_intents.ts";
|
||||
import { Collection } from "../../../util/collection.ts";
|
||||
import { threadMemberModified } from "../../../util/transformers/thread_member_modified.ts";
|
||||
// import { threadMemberModified } from "../../../util/transformers/thread_member_modified.ts";
|
||||
|
||||
/** Returns thread members objects that are members of the thread. */
|
||||
export async function getThreadMembers(bot: Bot, threadId: bigint) {
|
||||
// Check if intents is not 0 as proxy ws won't set intents in other instances
|
||||
if (
|
||||
bot.gateway.identifyPayload.intents &&
|
||||
!(bot.gateway.identifyPayload.intents & DiscordGatewayIntents.GuildMembers)
|
||||
) {
|
||||
throw new Error(bot.constants.Errors.MISSING_INTENT_GUILD_MEMBERS);
|
||||
}
|
||||
|
||||
const thread = await bot.cache.threads.get(threadId);
|
||||
if (thread?.isPrivate) {
|
||||
const channel = await bot.cache.channels.get(thread.parentId);
|
||||
if (channel && !(await bot.utils.botHasChannelPermissions(bot, channel, ["MANAGE_THREADS"])) && !thread.botIsMember)
|
||||
throw new Error(bot.constants.Errors.CANNOT_GET_MEMBERS_OF_AN_UNJOINED_PRIVATE_THREAD);
|
||||
}
|
||||
|
||||
const result = await bot.rest.runMethod<ThreadMember[]>(
|
||||
bot.rest,
|
||||
"get",
|
||||
bot.constants.endpoints.THREAD_MEMBERS(threadId)
|
||||
);
|
||||
|
||||
const members = result.map((member) => threadMemberModified(member));
|
||||
|
||||
return new Collection(members.map((member) => [member.id, member]));
|
||||
// // Check if intents is not 0 as proxy ws won't set intents in other instances
|
||||
// if (
|
||||
// bot.gateway.identifyPayload.intents &&
|
||||
// !(bot.gateway.identifyPayload.intents & DiscordGatewayIntents.GuildMembers)
|
||||
// ) {
|
||||
// throw new Error(bot.constants.Errors.MISSING_INTENT_GUILD_MEMBERS);
|
||||
// }
|
||||
|
||||
// const thread = await bot.cache.threads.get(threadId);
|
||||
// if (thread?.isPrivate) {
|
||||
// const channel = await bot.cache.channels.get(thread.parentId);
|
||||
// if (channel && !(await bot.utils.botHasChannelPermissions(bot, channel, ["MANAGE_THREADS"])) && !thread.botIsMember)
|
||||
// throw new Error(bot.constants.Errors.CANNOT_GET_MEMBERS_OF_AN_UNJOINED_PRIVATE_THREAD);
|
||||
// }
|
||||
|
||||
// const result = await bot.rest.runMethod<ThreadMember[]>(
|
||||
// bot.rest,
|
||||
// "get",
|
||||
// bot.constants.endpoints.THREAD_MEMBERS(threadId)
|
||||
// );
|
||||
|
||||
// const members = result.map((member) => threadMemberModified(member));
|
||||
|
||||
// return new Collection(members.map((member) => [member.id, member]));
|
||||
}
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
import type { Channel } from "../../../types/channels/channel.ts";
|
||||
import type { StartThread } from "../../../types/channels/threads/start_thread.ts";
|
||||
import type { Bot } from "../../../bot.ts";
|
||||
import { channelToThread } from "../../../util/transformers/channel_to_thread.ts";
|
||||
|
||||
/** Creates a new private thread. Returns a thread channel. */
|
||||
export async function startPrivateThread(bot: Bot, channelId: bigint, options: StartThread) {
|
||||
const channel = await bot.cache.channels.get(channelId);
|
||||
if (channel) {
|
||||
if (!channel.isGuildTextBasedChannel) throw new Error(bot.constants.Errors.INVALID_THREAD_PARENT_CHANNEL_TYPE);
|
||||
// const channel = await bot.cache.channels.get(channelId);
|
||||
// if (channel) {
|
||||
// if (!channel.isGuildTextBasedChannel) throw new Error(bot.constants.Errors.INVALID_THREAD_PARENT_CHANNEL_TYPE);
|
||||
|
||||
if (channel.isNewsChannel) throw new Error(bot.constants.Errors.GUILD_NEWS_CHANNEL_ONLY_SUPPORT_PUBLIC_THREADS);
|
||||
// if (channel.isNewsChannel) throw new Error(bot.constants.Errors.GUILD_NEWS_CHANNEL_ONLY_SUPPORT_PUBLIC_THREADS);
|
||||
|
||||
await bot.utils.requireBotChannelPermissions(bot, channel, ["SEND_MESSAGES", "USE_PRIVATE_THREADS"]);
|
||||
}
|
||||
|
||||
return channelToThread(
|
||||
await bot.rest.runMethod<Channel>(bot.rest, "post", bot.constants.endpoints.THREAD_START_PRIVATE(channelId), {
|
||||
name: options.name,
|
||||
auto_archive_duration: options.autoArchiveDuration,
|
||||
})
|
||||
);
|
||||
// await bot.utils.requireBotChannelPermissions(bot, channel, ["SEND_MESSAGES", "USE_PRIVATE_THREADS"]);
|
||||
// }
|
||||
|
||||
// return channelToThread(
|
||||
// await bot.rest.runMethod<Channel>(bot.rest, "post", bot.constants.endpoints.THREAD_START_PRIVATE(channelId), {
|
||||
// name: options.name,
|
||||
// auto_archive_duration: options.autoArchiveDuration,
|
||||
// })
|
||||
// );
|
||||
}
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
import type { Channel } from "../../../types/channels/channel.ts";
|
||||
import type { StartThread } from "../../../types/channels/threads/start_thread.ts";
|
||||
import type { Bot } from "../../../bot.ts";
|
||||
import { channelToThread } from "../../../util/transformers/channel_to_thread.ts";
|
||||
|
||||
/** Creates a new public thread from an existing message. Returns a thread channel. */
|
||||
export async function startThread(bot: Bot, channelId: bigint, messageId: bigint, options: StartThread) {
|
||||
const channel = await bot.cache.channels.get(channelId);
|
||||
if (channel) {
|
||||
if (!channel.isGuildTextBasedChannel) {
|
||||
throw new Error(bot.constants.Errors.INVALID_THREAD_PARENT_CHANNEL_TYPE);
|
||||
}
|
||||
// const channel = await bot.cache.channels.get(channelId);
|
||||
// if (channel) {
|
||||
// if (!channel.isGuildTextBasedChannel) {
|
||||
// throw new Error(bot.constants.Errors.INVALID_THREAD_PARENT_CHANNEL_TYPE);
|
||||
// }
|
||||
|
||||
await bot.utils.requireBotChannelPermissions(bot, channel, ["SEND_MESSAGES", "USE_PUBLIC_THREADS"]);
|
||||
}
|
||||
// await bot.utils.requireBotChannelPermissions(bot, channel, ["SEND_MESSAGES", "USE_PUBLIC_THREADS"]);
|
||||
// }
|
||||
|
||||
return channelToThread(
|
||||
await bot.rest.runMethod<Channel>(
|
||||
bot.rest,
|
||||
"post",
|
||||
bot.constants.endpoints.THREAD_START_PUBLIC(channelId, messageId),
|
||||
{
|
||||
name: options.name,
|
||||
auto_archive_duration: options.autoArchiveDuration,
|
||||
}
|
||||
)
|
||||
);
|
||||
// return channelToThread(
|
||||
// await bot.rest.runMethod<Channel>(
|
||||
// bot.rest,
|
||||
// "post",
|
||||
// bot.constants.endpoints.THREAD_START_PUBLIC(channelId, messageId),
|
||||
// {
|
||||
// name: options.name,
|
||||
// auto_archive_duration: options.autoArchiveDuration,
|
||||
// }
|
||||
// )
|
||||
// );
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
// import { cacheHandlers } from "../../cache.ts";
|
||||
import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Delete a message with the channel id and message id only. */
|
||||
@@ -9,7 +9,7 @@ export async function deleteMessage(
|
||||
reason?: string,
|
||||
delayMilliseconds = 0
|
||||
) {
|
||||
const message = await cacheHandlers.get("messages", messageId);
|
||||
const message = await bot.cache.messages.get(messageId);
|
||||
|
||||
if (message && message.authorId !== bot.id) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, message.channelId, ["MANAGE_MESSAGES"]);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
// import { cacheHandlers } from "../../cache.ts";
|
||||
import type { EditMessage } from "../../types/messages/edit_message.ts";
|
||||
import type { Message } from "../../types/messages/message.ts";
|
||||
import type { PermissionStrings } from "../../types/permissions/permission_strings.ts";
|
||||
@@ -7,7 +7,7 @@ import type { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
/** Edit the message. */
|
||||
export async function editMessage(bot: Bot, channelId: bigint, messageId: bigint, content: string | EditMessage) {
|
||||
const message = await cacheHandlers.get("messages", messageId);
|
||||
const message = await bot.cache.messages.get(messageId);
|
||||
|
||||
if (message) {
|
||||
if (message.authorId !== bot.id) {
|
||||
@@ -34,7 +34,18 @@ export async function editMessage(bot: Bot, channelId: bigint, messageId: bigint
|
||||
bot.rest,
|
||||
"patch",
|
||||
bot.constants.endpoints.CHANNEL_MESSAGE(channelId, messageId),
|
||||
bot.utils.snakelize(content)
|
||||
{
|
||||
content: content.content,
|
||||
embeds: content.embeds,
|
||||
allowed_mentions: {
|
||||
parse: content.allowedMentions?.parse,
|
||||
roles: content.allowedMentions?.roles,
|
||||
users: content.allowedMentions?.users,
|
||||
replied_user: content.allowedMentions?.repliedUser,
|
||||
},
|
||||
file: content.file,
|
||||
components: content.components,
|
||||
}
|
||||
);
|
||||
|
||||
return bot.transformers.message(bot, result);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
// import { cacheHandlers } from "../../cache.ts";
|
||||
import type { Message } from "../../types/messages/message.ts";
|
||||
import type { Bot } from "../../bot.ts";
|
||||
import type { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
/** Fetch a single message from the server. Requires VIEW_CHANNEL and READ_MESSAGE_HISTORY */
|
||||
export async function getMessage(bot: Bot, channelId: bigint, id: bigint) {
|
||||
if (await cacheHandlers.has("channels", channelId)) {
|
||||
if (await bot.cache.channels.has(channelId)) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["VIEW_CHANNEL", "READ_MESSAGE_HISTORY"]);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
// import { cacheHandlers } from "../../cache.ts";
|
||||
import { DiscordChannelTypes } from "../../types/channels/channel_types.ts";
|
||||
import { Errors } from "../../types/discordeno/errors.ts";
|
||||
import { DiscordAllowedMentionsTypes } from "../../types/messages/allowed_mentions_types.ts";
|
||||
@@ -12,7 +12,7 @@ import type { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
export async function sendMessage(bot: Bot, channelId: bigint, content: string | CreateMessage) {
|
||||
if (typeof content === "string") content = { content };
|
||||
|
||||
const channel = await cacheHandlers.get("channels", channelId);
|
||||
const channel = await bot.cache.channels.get(channelId);
|
||||
if (channel) {
|
||||
if (
|
||||
![
|
||||
@@ -77,15 +77,15 @@ export async function sendMessage(bot: Bot, channelId: bigint, content: string |
|
||||
bot.rest,
|
||||
"post",
|
||||
bot.constants.endpoints.CHANNEL_MESSAGES(channelId),
|
||||
bot.utils.snakelize({
|
||||
{
|
||||
content: content.content,
|
||||
tts: content.tts,
|
||||
embeds: content.embeds,
|
||||
allowed_mentions: {
|
||||
parse: content.allowedMentions.parse,
|
||||
roles: content.allowedMentions.roles,
|
||||
users: content.allowedMentions.users,
|
||||
replied_user: content.allowedMentions.repliedUser,
|
||||
parse: content.allowedMentions?.parse,
|
||||
roles: content.allowedMentions?.roles,
|
||||
users: content.allowedMentions?.users,
|
||||
replied_user: content.allowedMentions?.repliedUser,
|
||||
},
|
||||
file: content.file,
|
||||
// TODO: Snakelize components??
|
||||
@@ -100,7 +100,7 @@ export async function sendMessage(bot: Bot, channelId: bigint, content: string |
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
return bot.transformers.message(bot, result);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { Bot } from "../../bot.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
// import { cacheHandlers } from "../../cache.ts";
|
||||
import type { Message } from "../../types/messages/message.ts";
|
||||
import type { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
/** Suppress all the embeds in this message */
|
||||
export async function suppressEmbeds(bot: Bot, channelId: bigint, messageId: bigint) {
|
||||
const message = await cacheHandlers.get("messages", messageId);
|
||||
const message = await bot.cache.messages.get(messageId);
|
||||
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, message ? ["MANAGE_MESSAGES"] : ["SEND_MESSAGES"]);
|
||||
|
||||
|
||||
+86
-24
@@ -1,13 +1,10 @@
|
||||
import { Bot } from "../bot.ts";
|
||||
import type { PresenceUpdate } from "../types/activity/presence_update.ts";
|
||||
import type { Emoji } from "../types/emojis/emoji.ts";
|
||||
import type { Guild } from "../types/guilds/guild.ts";
|
||||
import { Collection } from "../util/collection.ts";
|
||||
import { iconHashToBigInt } from "../util/hash.ts";
|
||||
import { channelToThread } from "../util/transformers/channel_to_thread.ts";
|
||||
import { transformChannel } from "./channel.ts";
|
||||
import { DiscordenoRole, transformRole } from "./role.ts";
|
||||
import { DiscordenoVoiceState, transformVoiceState } from "./voice_state.ts";
|
||||
import { DiscordenoRole } from "./role.ts";
|
||||
import { DiscordenoVoiceState } from "./voice_state.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../types/util.ts";
|
||||
|
||||
export function transformGuild(
|
||||
@@ -31,11 +28,34 @@ export function transformGuild(
|
||||
preferredLocale: payload.guild.preferred_locale,
|
||||
premiumSubscriptionCount: payload.guild.premium_subscription_count,
|
||||
premiumTier: payload.guild.premium_tier,
|
||||
stageInstances: payload.guild.stage_instances,
|
||||
stageInstances: payload.guild.stage_instances?.map((si) => ({
|
||||
/** The id of this Stage instance */
|
||||
id: bot.transformers.snowflake(si.id),
|
||||
/** The guild id of the associated Stage channel */
|
||||
guildId: bot.transformers.snowflake(si.guild_id),
|
||||
/** The id of the associated Stage channel */
|
||||
channelId: bot.transformers.snowflake(si.channel_id),
|
||||
/** The topic of the Stage instance (1-120 characters) */
|
||||
topic: si.topic,
|
||||
/** The privacy level of the Stage instance */
|
||||
privacyLevel: si.privacy_level,
|
||||
/** Whether or not Stage discovery is disabled */
|
||||
discoverableDisabled: si.discoverable_disabled,
|
||||
})),
|
||||
systemChannelFlags: payload.guild.system_channel_flags,
|
||||
vanityUrlCode: payload.guild.vanity_url_code,
|
||||
verificationLevel: payload.guild.verification_level,
|
||||
welcomeScreen: payload.guild.welcome_screen,
|
||||
welcomeScreen: payload.guild.welcome_screen
|
||||
? {
|
||||
description: payload.guild.welcome_screen.description ?? undefined,
|
||||
welcomeChannels: payload.guild.welcome_screen.welcome_channels.map((wc) => ({
|
||||
channelId: bot.transformers.snowflake(wc.channel_id),
|
||||
description: wc.description,
|
||||
emojiId: wc.emoji_id ? bot.transformers.snowflake(wc.emoji_id) : undefined,
|
||||
emojiName: wc.emoji_name ?? undefined,
|
||||
})),
|
||||
}
|
||||
: undefined,
|
||||
discoverySplash: payload.guild.discovery_splash,
|
||||
|
||||
bitfield:
|
||||
@@ -49,26 +69,31 @@ export function transformGuild(
|
||||
shardId: payload.shardId,
|
||||
icon: payload.guild.icon ? iconHashToBigInt(payload.guild.icon) : undefined,
|
||||
banner: payload.guild.banner ? iconHashToBigInt(payload.guild.banner) : undefined,
|
||||
splash: payload.guild.icon ? iconHashToBigInt(payload.guild.splash) : undefined,
|
||||
splash: payload.guild.splash ? iconHashToBigInt(payload.guild.splash) : undefined,
|
||||
|
||||
// TRANSFORMED STUFF BELOW
|
||||
// TODO: Handle channels/threads in a better way?
|
||||
channels: (payload.guild.channels || []).map((channel) =>
|
||||
transformChannel(bot, { channel, guildId: bot.transformers.snowflake(payload.guild.id) })
|
||||
),
|
||||
threads: (payload.guild.threads || []).map((channel) => channelToThread(channel)),
|
||||
// channels: (payload.guild.channels || []).map((channel) =>
|
||||
// bot.transformers.channel(bot, { channel, guildId: bot.transformers.snowflake(payload.guild.id) })
|
||||
// ),
|
||||
// threads: (payload.guild.threads || []).map((channel) => channelToThread(channel)),
|
||||
|
||||
roles: new Collection(
|
||||
(payload.guild.roles || [])
|
||||
.map((role) => transformRole(bot, { role, guildId: bot.transformers.snowflake(payload.guild.id) }))
|
||||
.map((role) => bot.transformers.role(bot, { role, guildId: bot.transformers.snowflake(payload.guild.id) }))
|
||||
.map((role) => [role.id, role])
|
||||
),
|
||||
presences: new Collection((payload.guild.presences || []).map((p) => [bot.transformers.snowflake(p.user!.id), p])),
|
||||
// presences: new Collection(
|
||||
// (payload.guild.presences || []).map((p) => [
|
||||
// bot.transformers.snowflake(p.user!.id),
|
||||
// bot.transformers.presence(bot, p),
|
||||
// ])
|
||||
// ),
|
||||
emojis: new Collection((payload.guild.emojis || []).map((emoji) => [bot.transformers.snowflake(emoji.id!), emoji])),
|
||||
voiceStates: new Collection(
|
||||
(payload.guild.voice_states || [])
|
||||
.map((vs) =>
|
||||
transformVoiceState(bot, { voiceState: vs, guildId: bot.transformers.snowflake(payload.guild.id) })
|
||||
bot.transformers.voiceState(bot, { voiceState: vs, guildId: bot.transformers.snowflake(payload.guild.id) })
|
||||
)
|
||||
.map((vs) => [vs.userId, vs])
|
||||
),
|
||||
@@ -113,6 +138,13 @@ export interface DiscordenoGuild
|
||||
| "systemChannelId"
|
||||
| "rulesChannelId"
|
||||
| "publicUpdatesChannelId"
|
||||
| "joinedAt"
|
||||
| "icon"
|
||||
| "banner"
|
||||
| "splash"
|
||||
| "stageInstances"
|
||||
| "welcomeScreen"
|
||||
| "channels"
|
||||
> {
|
||||
/** Guild id */
|
||||
id: bigint;
|
||||
@@ -132,12 +164,6 @@ export interface DiscordenoGuild
|
||||
rulesChannelId?: bigint;
|
||||
/** The id of the channel where admins and moderators of Community guilds receive notices from Discord */
|
||||
publicUpdatesChannelId?: bigint;
|
||||
/** Whether this server's icon is animated */
|
||||
animatedIcon: boolean;
|
||||
/** Whether this server's banner is animated. */
|
||||
animatedBanner: boolean;
|
||||
/** Whether this server's splash is animated. */
|
||||
animatedSplash: boolean;
|
||||
/** The id of the shard this guild is bound to */
|
||||
shardId: number;
|
||||
/** Total number of members in this guild */
|
||||
@@ -145,13 +171,49 @@ export interface DiscordenoGuild
|
||||
/** The roles in the guild */
|
||||
roles: Collection<bigint, DiscordenoRole>;
|
||||
/** The presences of all the users in the guild. */
|
||||
presences: Collection<bigint, PresenceUpdate>;
|
||||
// presences: Collection<bigint, DiscordenoPresence>;
|
||||
/** The Voice State data for each user in a voice channel in this server. */
|
||||
voiceStates: Collection<bigint, DiscordenoVoiceState>;
|
||||
/** Custom guild emojis */
|
||||
emojis: Collection<bigint, Emoji>;
|
||||
/** Whether the bot is the owner of this guild */
|
||||
isOwner: boolean;
|
||||
/** Holds all the boolean toggles. */
|
||||
bitfield: bigint;
|
||||
/** When this guild was joined at */
|
||||
joinedAt?: number;
|
||||
/** Icon hash */
|
||||
icon?: bigint;
|
||||
/** Splash hash */
|
||||
splash?: bigint;
|
||||
/** Banner hash */
|
||||
banner?: bigint;
|
||||
/** The stage instances in this guild */
|
||||
stageInstances?: {
|
||||
/** The id of this Stage instance */
|
||||
id: bigint;
|
||||
/** The guild id of the associated Stage channel */
|
||||
guildId: bigint;
|
||||
/** The id of the associated Stage channel */
|
||||
channelId: bigint;
|
||||
/** The topic of the Stage instance (1-120 characters) */
|
||||
topic: string;
|
||||
/** The privacy level of the Stage instance */
|
||||
privacyLevel: number;
|
||||
/** Whether or not Stage discovery is disabled */
|
||||
discoverableDisabled: boolean;
|
||||
}[];
|
||||
welcomeScreen?: {
|
||||
/** The server description shown in the welcome screen */
|
||||
description?: string;
|
||||
/** The channels shown in the welcome screen, up to 5 */
|
||||
welcomeChannels: {
|
||||
/** The channel's id */
|
||||
channelId: bigint;
|
||||
/** The descriptino schown for the channel */
|
||||
description: string;
|
||||
/** The emoji id, if the emoji is custom */
|
||||
emojiId?: bigint;
|
||||
/** The emoji name if custom, the unicode character if standard, or `null` if no emoji is set */
|
||||
emojiName?: string;
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { SnakeCasedPropertiesDeep } from "../types/util.ts";
|
||||
export function transformVoiceState(
|
||||
bot: Bot,
|
||||
payload: { voiceState: SnakeCasedPropertiesDeep<VoiceState> } & { guildId: bigint }
|
||||
) {
|
||||
): DiscordenoVoiceState {
|
||||
return {
|
||||
bitfield:
|
||||
(payload.voiceState.deaf ? 1n : 0n) |
|
||||
@@ -40,4 +40,6 @@ export interface DiscordenoVoiceState {
|
||||
bitfield: bigint;
|
||||
/** The time at which the user requested to speak */
|
||||
requestToSpeakTimestamp?: number;
|
||||
/** The unique session id */
|
||||
sessionId: string;
|
||||
}
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
import { DiscordenoThread } from "../../util/transformers/channel_to_thread.ts";
|
||||
import type { Collection } from "../../util/collection.ts";
|
||||
import type { PresenceUpdate } from "../activity/presence_update.ts";
|
||||
import type { StageInstance } from "../channels/stage_instance.ts";
|
||||
import type { ThreadMemberModified } from "../channels/threads/thread_member.ts";
|
||||
import type { ThreadMembersUpdateModified } from "../channels/threads/thread_members_update.ts";
|
||||
import type { Emoji } from "../emojis/emoji.ts";
|
||||
import type { GatewayPayload } from "../gateway/gateway_payload.ts";
|
||||
import type { DiscordGatewayPayload } from "../gateway/gateway_payload.ts";
|
||||
import type { IntegrationCreateUpdate } from "../integrations/integration_create_update.ts";
|
||||
import type { IntegrationDelete } from "../integrations/integration_delete.ts";
|
||||
import type { ApplicationCommandCreateUpdateDelete } from "../interactions/commands/application_command_create_update_delete.ts";
|
||||
import type { BigInteraction, Interaction } from "../interactions/interaction.ts";
|
||||
import type { InviteCreate } from "../invites/invite_create.ts";
|
||||
import type { InviteDelete } from "../invites/invite_delete.ts";
|
||||
import type { MessageReactionAdd } from "../messages/message_reaction_add.ts";
|
||||
import type { MessageReactionRemove } from "../messages/message_reaction_remove.ts";
|
||||
import type { MessageReactionRemoveAll } from "../messages/message_reaction_remove_all.ts";
|
||||
import type { TypingStart } from "../misc/typing_start.ts";
|
||||
import type { User } from "../users/user.ts";
|
||||
import type { VoiceServerUpdate } from "../voice/voice_server_update.ts";
|
||||
import type { VoiceState } from "../voice/voice_state.ts";
|
||||
import type { DebugArg } from "./debug_arg.ts";
|
||||
import type { GuildUpdateChange } from "./guild_update_change.ts";
|
||||
|
||||
export type EventHandlersDefinitions = {
|
||||
/** Sent when properties about the user change. */
|
||||
botUpdate: [user: User];
|
||||
/** Sent when a new guild channel is created, relevant to the current user. */
|
||||
channelCreate: [channel: DiscordenoChannel];
|
||||
/** Sent when a channel is updated. This is not sent when the field `last_message_id` is altered. To keep track of the `last_message_id` changes, you must listen for `MESSAGE_CREATE` events. */
|
||||
channelUpdate: [channel: DiscordenoChannel, oldChannel: DiscordenoChannel];
|
||||
/** Sent when a channel relevant to the current user is deleted. */
|
||||
channelDelete: [channel: DiscordenoChannel];
|
||||
/** Sent when a message pin is updated */
|
||||
channelPinsUpdate: [channel: DiscordenoChannel, guild?: DiscordenoGuild, lastPinTimestamp?: string | null];
|
||||
debug: [args: string | DebugArg, data?: string];
|
||||
/** Sent before every event. Discordeno awaits the execution of this event before main event gets sent. */
|
||||
dispatchRequirements: [data: DiscordGatewayPayload, shardId: number];
|
||||
/** Sent when a user is banned from a guild. */
|
||||
guildBanAdd: [guild: DiscordenoGuild, user: User, member?: DiscordenoMember];
|
||||
/** Sent when a user is unbanned from a guild. */
|
||||
guildBanRemove: [guild: DiscordenoGuild, user: User, member?: DiscordenoMember];
|
||||
/**
|
||||
* This event can be sent in three different scenarios:
|
||||
* 1. When a user is initially connecting, to lazily load and backfill information for all unavailable guilds sent in the `READY` event. Guilds that are unavailable due to an outage will send a `GUILD_DELETE` event.
|
||||
* 2. When a Guild becomes available again to the client.
|
||||
* 3. When the current user joins a new Guild.
|
||||
*
|
||||
* This event does not get sent on startup
|
||||
*/
|
||||
guildCreate: [guild: DiscordenoGuild];
|
||||
/** This event does get sent on start when shards are loading the guilds */
|
||||
guildLoaded: [guild: DiscordenoGuild];
|
||||
/** When a guild goes available this event will be ran. */
|
||||
guildAvailable: [guild: DiscordenoGuild];
|
||||
/** When a guild goes unavailable this event will be ran. */
|
||||
guildUnavailable: [guild: DiscordenoGuild];
|
||||
/** Sent when a guilds integration gets updated */
|
||||
guildIntegrationsUpdate: [guild: DiscordenoGuild];
|
||||
/** Sent when a guild is updated. */
|
||||
guildUpdate: [guild: DiscordenoGuild, changes: GuildUpdateChange[]];
|
||||
/** Sent when a guild becomes or was already unavailable due to an outage, or when the user leaves or is removed from a guild. If the `unavailable` field is not set, the user was removed from the guild. */
|
||||
guildDelete: [guild: DiscordenoGuild];
|
||||
/** Sent when a guild's emojis have been updated. */
|
||||
guildEmojisUpdate: [guild: DiscordenoGuild, emojis: Collection<bigint, Emoji>, oldEmojis: Collection<bigint, Emoji>];
|
||||
/** Sent when a new user joins a guild. */
|
||||
guildMemberAdd: [guild: DiscordenoGuild, member: DiscordenoMember];
|
||||
/** Sent when a user is removed from a guild (leave/kick/ban). */
|
||||
guildMemberRemove: [guild: DiscordenoGuild, user: User, member?: DiscordenoMember];
|
||||
/** Sent when a guild member is updated. This will also fire when the user object of a guild member changes. */
|
||||
guildMemberUpdate: [guild: DiscordenoGuild, member: DiscordenoMember, oldMember?: DiscordenoMember];
|
||||
/** Sent when a user uses a Slash Command (type 2) or clicks a button (type 3). */
|
||||
interactionCreate: [data: BigInteraction, member?: DiscordenoMember];
|
||||
/** Sent when a user uses a Slash Command in a guild (type 2) or clicks a button (type 3). */
|
||||
interactionGuildCreate: [data: BigInteraction, member: DiscordenoMember];
|
||||
/** Sent when a user uses a Slash Command in a dm (type 2) or clicks a button (type 3). */
|
||||
interactionDMCreate: [data: Omit<BigInteraction, "member">];
|
||||
/** Sent when a lurker joins/leaves/moves stage channels. */
|
||||
lurkerVoiceStateUpdate: [member: DiscordenoMember, voiceState: VoiceState];
|
||||
/** Sent when a message is created. */
|
||||
messageCreate: [message: DiscordenoMessage];
|
||||
/** Sent when a message is deleted. */
|
||||
messageDelete: [partial: { id: string; channel: DiscordenoChannel }, message?: DiscordenoMessage];
|
||||
/** Sent when a message is updated. */
|
||||
messageUpdate: [message: DiscordenoMessage, oldMessage: DiscordenoMessage];
|
||||
/** Sent when a user updates its nickname */
|
||||
nicknameUpdate: [guild: DiscordenoGuild, member: DiscordenoMember, nickname: string, oldNickname?: string];
|
||||
/** A user's presence is their current state on a guild. This event is sent when a user's presence or info, such as name or avatar, is updated. */
|
||||
presenceUpdate: [presence: PresenceUpdate, oldPresence?: PresenceUpdate];
|
||||
/** Sent before every event execution. Discordeno will not await its execution. */
|
||||
raw: [data: GatewayPayload];
|
||||
/** Sent when all shards went ready. */
|
||||
ready: [];
|
||||
/** Sent when a user adds a reaction to a message. */
|
||||
reactionAdd: [data: MessageReactionAdd, message?: DiscordenoMessage];
|
||||
/** Sent when a user removes a reaction from a message. */
|
||||
reactionRemove: [data: MessageReactionRemove, message?: DiscordenoMessage];
|
||||
/** Sent when a user explicitly removes all reactions from a message. */
|
||||
reactionRemoveAll: [payload: MessageReactionRemoveAll, message?: DiscordenoMessage];
|
||||
/** Sent when a bot removes all instances of a given emoji from the reactions of a message. */
|
||||
reactionRemoveEmoji: [emoji: Partial<Emoji>, messageId: bigint, channelId: bigint, guildId?: bigint];
|
||||
/** Sent when a guild role is created. */
|
||||
roleCreate: [guild: DiscordenoGuild, role: DiscordenoRole];
|
||||
/** Sent when a guild role is deleted. */
|
||||
roleDelete: [guild: DiscordenoGuild, role: DiscordenoRole];
|
||||
/** Sent when a guild role is updated. */
|
||||
roleUpdate: [guild: DiscordenoGuild, role: DiscordenoRole, old: DiscordenoRole];
|
||||
roleGained: [guild: DiscordenoGuild, member: DiscordenoMember, roleId: bigint];
|
||||
roleLost: [guild: DiscordenoGuild, member: DiscordenoMember, roleId: bigint];
|
||||
shardReady: [shardId: number];
|
||||
/** Sent when a shard failed to load. */
|
||||
shardFailedToLoad: [shardId: number, unavailableGuildIds: Set<bigint>];
|
||||
/** Sent when a Stage instance is created (i.e. the Stage is now "live"). */
|
||||
stageInstanceCreate: [instance: StageInstance];
|
||||
/** Sent when a Stage instance has been deleted (i.e. the Stage has been closed). */
|
||||
stageInstanceDelete: [instance: StageInstance];
|
||||
/** Sent when a Stage instance has been updated. */
|
||||
stageInstanceUpdate: [instance: StageInstance];
|
||||
/** Sent when a thread is created */
|
||||
threadCreate: [thread: DiscordenoThread];
|
||||
/** Sent when a thread is updated */
|
||||
threadUpdate: [thread: DiscordenoThread, oldThread: DiscordenoThread];
|
||||
/** Sent when the bot gains access to threads */
|
||||
threadListSync: [threads: Collection<bigint, DiscordenoThread>, members: ThreadMemberModified[], guildId: bigint];
|
||||
/** Sent when the current users thread member is updated */
|
||||
threadMemberUpdate: [threadMember: ThreadMemberModified, thread: DiscordenoThread];
|
||||
/** Sent when anyone is added to or removed from a thread */
|
||||
threadMembersUpdate: [update: ThreadMembersUpdateModified];
|
||||
/** Sent when a thread is deleted */
|
||||
threadDelete: [thread: DiscordenoThread];
|
||||
/** Sent when a user starts typing in a channel. */
|
||||
typingStart: [data: TypingStart];
|
||||
/** Sent when a user joins a voice channel */
|
||||
voiceChannelJoin: [member: DiscordenoMember, channelId: bigint];
|
||||
/** Sent when a user leaves a voice channel. Does not get sent when user switches the voice channel */
|
||||
voiceChannelLeave: [member: DiscordenoMember, channelId: bigint];
|
||||
/** Sent when a user switches the voice channel */
|
||||
voiceChannelSwitch: [member: DiscordenoMember, channelId: bigint, oldChannelId: bigint];
|
||||
/** Sent when a voice server is updated with information for making the bot connect to a voice channel. */
|
||||
voiceServerUpdate: [payload: VoiceServerUpdate, guild: DiscordenoGuild];
|
||||
/** Sent when someone joins/leaves/moves voice channels. */
|
||||
voiceStateUpdate: [member: DiscordenoMember, voiceState: VoiceState];
|
||||
/** Sent when a guild channel's webhook is created, updated, or deleted. */
|
||||
webhooksUpdate: [channelId: bigint, guildId: bigint];
|
||||
/** Sent when a member has passed the guild's Membership Screening requirements */
|
||||
membershipScreeningPassed: [guild: DiscordenoGuild, member: DiscordenoMember];
|
||||
/** Sent when an integration is created on a server such as twitch, youtube etc.. */
|
||||
integrationCreate: [data: IntegrationCreateUpdate];
|
||||
/** Sent when an integration is updated. */
|
||||
integrationUpdate: [data: IntegrationCreateUpdate];
|
||||
/** Sent when an integration is deleted. */
|
||||
integrationDelete: [data: IntegrationDelete];
|
||||
/** Sent when a new invite to a channel is created. */
|
||||
inviteCreate: [data: InviteCreate];
|
||||
/** Sent when an invite is deleted. */
|
||||
inviteDelete: [data: InviteDelete];
|
||||
};
|
||||
|
||||
export type EventHandlers = {
|
||||
[E in keyof EventHandlersDefinitions]?: (...args: EventHandlersDefinitions[E]) => unknown;
|
||||
};
|
||||
@@ -2,7 +2,6 @@ export * from "./create_slash_command.ts";
|
||||
export * from "./debug_arg.ts";
|
||||
export * from "./edit_webhook_message.ts";
|
||||
export * from "./errors.ts";
|
||||
export * from "./event_handlers.ts";
|
||||
export * from "./file_content.ts";
|
||||
export * from "./guild_member.ts";
|
||||
export * from "./guild_update_change.ts";
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/** https://discord.com/developers/docs/resources/guild#welcome-screen-object-welcome-screen-channel-structure */
|
||||
export interface WelcomeScreenChannel {
|
||||
/** The channel's id */
|
||||
channelId: bigint;
|
||||
channelId: string;
|
||||
/** The descriptino schown for the channel */
|
||||
description: string;
|
||||
/** The emoji id, if the emoji is custom */
|
||||
emojiId: bigint | null;
|
||||
emojiId: string | null;
|
||||
/** The emoji name if custom, the unicode character if standard, or `null` if no emoji is set */
|
||||
emojiName: string | null;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
export * from "./transformers/mod.ts";
|
||||
export * from "./bigint.ts";
|
||||
export * from "./cache_members.ts";
|
||||
export * from "./calculate_shard_id.ts";
|
||||
export * from "./collection.ts";
|
||||
export * from "./constants.ts";
|
||||
export * from "./dispatch_requirements.ts";
|
||||
export * from "./hash.ts";
|
||||
export * from "./loop_object.ts";
|
||||
export * from "./permissions.ts";
|
||||
export * from "./utils.ts";
|
||||
export * from "./validate_length.ts";
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
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";
|
||||
import { snowflakeToBigint } from "../bigint.ts";
|
||||
import { Collection } from "../collection.ts";
|
||||
import { createNewProp } from "../utils.ts";
|
||||
|
||||
export const threadToggles = {
|
||||
/** Whether this thread is archived. */
|
||||
archived: 1n,
|
||||
/** Whether this thread is locked. */
|
||||
locked: 2n,
|
||||
};
|
||||
|
||||
const baseThread: Partial<DiscordenoThread> = {
|
||||
get archived() {
|
||||
return Boolean(this.bitfield! & threadToggles.archived);
|
||||
},
|
||||
get locked() {
|
||||
return Boolean(this.bitfield! & threadToggles.locked);
|
||||
},
|
||||
get isPrivate() {
|
||||
return this.type === DiscordChannelTypes.GuildPrivateThread;
|
||||
},
|
||||
get isPublic() {
|
||||
return !this.isPrivate;
|
||||
},
|
||||
get guildId() {
|
||||
return cache.channels.get(this.parentId!)!.guildId;
|
||||
},
|
||||
toJSON() {
|
||||
return {
|
||||
id: this.id?.toString(),
|
||||
type: this.type,
|
||||
parentId: this.parentId?.toString(),
|
||||
memberCount: this.memberCount,
|
||||
messageCount: this.messageCount,
|
||||
archiveTimestamp: new Date(this.archiveTimestamp!).toISOString(),
|
||||
autoArchiveDuration: this.autoArchiveDuration,
|
||||
archived: this.archived,
|
||||
locked: this.locked,
|
||||
} as Thread;
|
||||
},
|
||||
};
|
||||
|
||||
export function channelToThread(channel: Channel) {
|
||||
let bitfield = 0n;
|
||||
|
||||
if (channel.threadMetadata?.archived) bitfield |= threadToggles.archived;
|
||||
if (channel.threadMetadata?.locked) bitfield |= threadToggles.locked;
|
||||
|
||||
return Object.create(baseThread, {
|
||||
id: createNewProp(snowflakeToBigint(channel.id)),
|
||||
type: createNewProp(channel.type),
|
||||
parentId: createNewProp(snowflakeToBigint(channel.parentId!)),
|
||||
memberCount: createNewProp(channel.memberCount),
|
||||
messageCount: createNewProp(channel.messageCount),
|
||||
archiveTimestamp: createNewProp(
|
||||
channel.threadMetadata?.archiveTimestamp ? Date.parse(channel.threadMetadata.archiveTimestamp) : undefined
|
||||
),
|
||||
autoArchiveDuration: createNewProp(channel.threadMetadata?.autoArchiveDuration || 0),
|
||||
bitfield: createNewProp(bitfield),
|
||||
ownerId: createNewProp(snowflakeToBigint(channel.ownerId!)),
|
||||
botIsMember: createNewProp(Boolean(channel.member)),
|
||||
members: createNewProp(new Collection<bigint, Omit<ThreadMemberModified, "id">>()),
|
||||
}) as DiscordenoThread;
|
||||
}
|
||||
|
||||
export interface Thread {
|
||||
id: string;
|
||||
type:
|
||||
| DiscordChannelTypes.GuildNewsThread
|
||||
| DiscordChannelTypes.GuildPublicThread
|
||||
| DiscordChannelTypes.GuildPrivateThread;
|
||||
parentId: string;
|
||||
memberCount: number;
|
||||
messageCount: number;
|
||||
archiveTimestamp: string;
|
||||
autoArchiveDuration: number;
|
||||
archived: boolean;
|
||||
locked: boolean;
|
||||
ownerId: string;
|
||||
botIsMember: boolean;
|
||||
}
|
||||
|
||||
export interface DiscordenoThread {
|
||||
id: bigint;
|
||||
type:
|
||||
| DiscordChannelTypes.GuildNewsThread
|
||||
| DiscordChannelTypes.GuildPublicThread
|
||||
| DiscordChannelTypes.GuildPrivateThread;
|
||||
parentId: bigint;
|
||||
memberCount: number;
|
||||
messageCount: number;
|
||||
archiveTimestamp: number;
|
||||
autoArchiveDuration: number;
|
||||
archived: boolean;
|
||||
locked: boolean;
|
||||
bitfield: bigint;
|
||||
ownerId: bigint;
|
||||
isPrivate: boolean;
|
||||
isPublic: boolean;
|
||||
botIsMember: boolean;
|
||||
guildId: bigint;
|
||||
members: Collection<bigint, Omit<ThreadMemberModified, "id">>;
|
||||
toJSON(): Thread;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from "./channel_to_thread.ts";
|
||||
export * from "./thread_member_modified.ts";
|
||||
export * from "./thread_members_update_modified.ts";
|
||||
@@ -1,11 +0,0 @@
|
||||
import { ThreadMember, ThreadMemberModified } from "../../types/channels/threads/thread_member.ts";
|
||||
import { snowflakeToBigint } from "../bigint.ts";
|
||||
|
||||
export function threadMemberModified(member: ThreadMember) {
|
||||
return {
|
||||
...member,
|
||||
id: snowflakeToBigint(member.id!),
|
||||
userId: snowflakeToBigint(member.userId!),
|
||||
joinTimestamp: Date.parse(member.joinTimestamp),
|
||||
} as ThreadMemberModified;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import {
|
||||
ThreadMembersUpdate,
|
||||
ThreadMembersUpdateModified,
|
||||
} from "../../types/channels/threads/thread_members_update.ts";
|
||||
import { snowflakeToBigint } from "../bigint.ts";
|
||||
import { threadMemberModified } from "./thread_member_modified.ts";
|
||||
|
||||
export function threadMembersUpdateModified(data: ThreadMembersUpdate) {
|
||||
return {
|
||||
...data,
|
||||
id: snowflakeToBigint(data.id),
|
||||
guildId: snowflakeToBigint(data.guildId),
|
||||
addedMembers: data.addedMembers?.map((member) => threadMemberModified(member)) || [],
|
||||
removedMemberIds: data.removedMemberIds?.map((id) => snowflakeToBigint(id)) || [],
|
||||
} as ThreadMembersUpdateModified;
|
||||
}
|
||||
+14
-11
@@ -1,15 +1,15 @@
|
||||
import { DiscordGatewayIntents } from "../types/gateway/gateway_intents.ts";
|
||||
import type { GetGatewayBot } from "../types/gateway/get_gateway_bot.ts";
|
||||
import { camelize } from "../util/utils.ts";
|
||||
import { StartGatewayOptions } from "./start_gateway_options.ts";
|
||||
import { GatewayManager } from "../bot.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../types/util.ts";
|
||||
|
||||
/** ADVANCED DEVS ONLY!!!!!!
|
||||
* Starts the standalone gateway.
|
||||
* This will require starting the bot separately.
|
||||
*/
|
||||
export async function startGateway(gateway: GatewayManager, options: StartGatewayOptions) {
|
||||
gateway.identifyPayload.token = `Bot ${options.token}`;
|
||||
gateway.token = `Bot ${options.token}`;
|
||||
gateway.secretKey = options.secretKey;
|
||||
gateway.firstShardId = options.firstShardId;
|
||||
gateway.url = options.url;
|
||||
@@ -17,25 +17,28 @@ export async function startGateway(gateway: GatewayManager, options: StartGatewa
|
||||
if (options.maxClusters) gateway.maxClusters = options.maxClusters;
|
||||
|
||||
if (options.compress) {
|
||||
gateway.identifyPayload.compress = options.compress;
|
||||
gateway.compress = options.compress;
|
||||
}
|
||||
if (options.reshard) gateway.reshard = options.reshard;
|
||||
// Once an hour check if resharding is necessary
|
||||
setInterval(() => gateway.resharder(gateway), 1000 * 60 * 60);
|
||||
|
||||
gateway.identifyPayload.intents = options.intents.reduce(
|
||||
gateway.intents = options.intents.reduce(
|
||||
(bits, next) => (bits |= typeof next === "string" ? DiscordGatewayIntents[next] : next),
|
||||
0
|
||||
);
|
||||
|
||||
gateway.botGatewayData = camelize(
|
||||
await fetch(`https://discord.com/api/gateway/bot`, {
|
||||
headers: { Authorization: gateway.identifyPayload.token },
|
||||
}).then((res) => res.json())
|
||||
) as GetGatewayBot;
|
||||
const result = (await fetch(`https://discord.com/api/gateway/bot`, {
|
||||
headers: { Authorization: gateway.token },
|
||||
}).then((res) => res.json())) as SnakeCasedPropertiesDeep<GetGatewayBot>;
|
||||
|
||||
gateway.maxShards = options.maxShards || gateway.botGatewayData.shards;
|
||||
gateway.lastShardId = options.lastShardId || gateway.botGatewayData.shards - 1;
|
||||
gateway.url = result.url;
|
||||
gateway.sessionStartLimitTotal = result.session_start_limit.total;
|
||||
gateway.sessionStartLimitRemaining = result.session_start_limit.remaining;
|
||||
gateway.sessionStartLimitResetAfter = result.session_start_limit.reset_after;
|
||||
gateway.maxConcurrency = result.session_start_limit.max_concurrency;
|
||||
gateway.maxShards = options.maxShards || result.shards;
|
||||
gateway.lastShardId = options.lastShardId || result.shards - 1;
|
||||
|
||||
gateway.spawnShards(gateway, gateway.firstShardId);
|
||||
}
|
||||
|
||||
-122
@@ -1,126 +1,4 @@
|
||||
import { DiscordGatewayOpcodes } from "../types/codes/gateway_opcodes.ts";
|
||||
import { Collection } from "../util/collection.ts";
|
||||
import { closeWS } from "./close_ws.ts";
|
||||
import { createShard } from "./create_shard.ts";
|
||||
import { log } from "./events.ts";
|
||||
import { handleDiscordPayload } from "./handle_discord_payload.ts";
|
||||
import { handleOnMessage } from "./handle_on_message.ts";
|
||||
import { heartbeat } from "./heartbeat.ts";
|
||||
import { identify } from "./identify.ts";
|
||||
import { processQueue } from "./process_queue.ts";
|
||||
import { resharder } from "./resharder.ts";
|
||||
import { sendShardMessage } from "./send_shard_message.ts";
|
||||
import { spawnShards } from "./spawn_shards.ts";
|
||||
import { startGateway } from "./start_gateway.ts";
|
||||
import { tellClusterToIdentify } from "./tell_cluster_to_identify.ts";
|
||||
import { resume } from "./resume.ts";
|
||||
|
||||
// CONTROLLER LIKE INTERFACE FOR WS HANDLING
|
||||
export const ws = {
|
||||
/** The secret key authorization header the bot will expect when sending payloads. */
|
||||
secretKey: "",
|
||||
/** The url that all discord payloads for the dispatch type should be sent to. */
|
||||
url: "",
|
||||
/** Whether or not to automatically reshard. */
|
||||
reshard: true,
|
||||
/** The percentage at which resharding should occur. */
|
||||
reshardPercentage: 80,
|
||||
/** The delay in milliseconds to wait before spawning next shard. OPTIMAL IS ABOVE 2500. YOU DON"T WANT TO HIT THE RATE LIMIT!!! */
|
||||
spawnShardDelay: 2600,
|
||||
/** The maximum shard Id number. Useful for zero-downtime updates or resharding. */
|
||||
maxShards: 0,
|
||||
/** Whether or not the resharder should automatically switch to LARGE BOT SHARDING when you are above 100K servers. */
|
||||
useOptimalLargeBotSharding: true,
|
||||
/** The amount of shards to load per cluster. */
|
||||
shardsPerCluster: 25,
|
||||
/** The maximum amount of clusters to use for your bot. */
|
||||
maxClusters: 4,
|
||||
/** The first shard Id to start spawning. */
|
||||
firstShardId: 0,
|
||||
/** The last shard Id for this cluster. */
|
||||
lastShardId: 1,
|
||||
/** The identify payload holds the necessary data to connect and stay connected with Discords WSS. */
|
||||
identifyPayload: {
|
||||
token: "",
|
||||
compress: false,
|
||||
properties: {
|
||||
$os: "linux",
|
||||
$browser: "Discordeno",
|
||||
$device: "Discordeno",
|
||||
},
|
||||
intents: 0,
|
||||
shard: [0, 0],
|
||||
},
|
||||
botGatewayData: {
|
||||
/** The WSS URL that can be used for connecting to the gateway. */
|
||||
url: "wss://gateway.discord.gg/?v=9&encoding=json",
|
||||
/** The recommended number of shards to use when connecting. */
|
||||
shards: 1,
|
||||
/** Info on the current start limit. */
|
||||
sessionStartLimit: {
|
||||
/** The total number of session starts the current user is allowed. */
|
||||
total: 1000,
|
||||
/** The remaining number of session starts the current user is allowed. */
|
||||
remaining: 1000,
|
||||
/** Milliseconds left until limit is reset. */
|
||||
resetAfter: 0,
|
||||
/** The number of identify requests allowed per 5 seconds.
|
||||
* So, if you had a max concurrency of 16, and 16 shards for example, you could start them all up at the same time.
|
||||
* Whereas if you had 32 shards, if you tried to start up shard 0 and 16 at the same time for example, it would not work. You can start shards 0-15 concurrently, then 16-31...
|
||||
*/
|
||||
maxConcurrency: 1,
|
||||
},
|
||||
},
|
||||
shards: new Collection<number, DiscordenoShard>(),
|
||||
loadingShards: new Collection<
|
||||
number,
|
||||
{
|
||||
shardId: number;
|
||||
resolve: (value: unknown) => void;
|
||||
startedAt: number;
|
||||
}
|
||||
>(),
|
||||
/** Stored as bucketId: { clusters: [clusterId, [ShardIds]], createNextShard: boolean } */
|
||||
buckets: new Collection<
|
||||
number,
|
||||
{
|
||||
clusters: number[][];
|
||||
createNextShard: (() => unknown)[];
|
||||
}
|
||||
>(),
|
||||
utf8decoder: new TextDecoder(),
|
||||
|
||||
// METHODS
|
||||
|
||||
/** The handler function that starts the gateway. */
|
||||
startGateway,
|
||||
/** The handler for spawning ALL the shards. */
|
||||
spawnShards,
|
||||
/** Create the websocket and adds the proper handlers to the websocket. */
|
||||
createShard,
|
||||
/** Begins identification of the shard to discord. */
|
||||
identify,
|
||||
/** Begins heartbeating of the shard to keep it alive. */
|
||||
heartbeat,
|
||||
/** Sends the discord payload to another server. */
|
||||
handleDiscordPayload,
|
||||
/** Tell the cluster/worker to begin identifying this shard */
|
||||
tellClusterToIdentify,
|
||||
/** Handle the different logs. Used for debugging. */
|
||||
log,
|
||||
/** Handles resharding the bot when necessary. */
|
||||
resharder,
|
||||
/** Handles the message events from websocket. */
|
||||
handleOnMessage,
|
||||
/** Handles processing queue of requests send to this shard. */
|
||||
processQueue,
|
||||
/** Closes shard WebSocket connection properly. */
|
||||
closeWS,
|
||||
/** Properly adds a message to the shards queue. */
|
||||
sendShardMessage,
|
||||
/** Properly resume an old shards session. */
|
||||
resume,
|
||||
};
|
||||
|
||||
export interface DiscordenoShard {
|
||||
/** The shard id number. */
|
||||
|
||||
+15
-17
@@ -1,22 +1,20 @@
|
||||
// THE ORDER OF THE IMPORTS IN THIS FILE MATTER!
|
||||
// DO NOT MOVE THEM UNLESS YOU KNOW WHAT YOUR DOING!
|
||||
// // THE ORDER OF THE IMPORTS IN THIS FILE MATTER!
|
||||
// // DO NOT MOVE THEM UNLESS YOU KNOW WHAT YOUR DOING!
|
||||
|
||||
import "./util/utils.ts";
|
||||
import "./util/validate_length.ts";
|
||||
import "./util/loop_object.ts";
|
||||
// import "./util/utils.ts";
|
||||
// import "./util/validate_length.ts";
|
||||
// import "./util/loop_object.ts";
|
||||
|
||||
// Final cleanup
|
||||
// // Final cleanup
|
||||
|
||||
import { cache } from "../src/cache.ts";
|
||||
import { delay } from "../src/util/utils.ts";
|
||||
if (import.meta.main) {
|
||||
// clear all the sweeper intervals
|
||||
for (const c of Object.values(cache)) {
|
||||
if (!(c instanceof Map)) continue;
|
||||
// import { delay } from "../src/util/utils.ts";
|
||||
// if (import.meta.main) {
|
||||
// // clear all the sweeper intervals
|
||||
// for (const c of Object.values(cache)) {
|
||||
// if (!(c instanceof Map)) continue;
|
||||
|
||||
c.stopSweeper();
|
||||
console.log("Cleaned");
|
||||
}
|
||||
// console.log("Cleaned");
|
||||
// }
|
||||
|
||||
await delay(3000);
|
||||
}
|
||||
// await delay(3000);
|
||||
// }
|
||||
|
||||
+105
-76
@@ -1,90 +1,119 @@
|
||||
// THE ORDER OF THE IMPORTS IN THIS FILE MATTER!
|
||||
// DO NOT MOVE THEM UNLESS YOU KNOW WHAT YOUR DOING!
|
||||
import { TOKEN } from "../configs.ts";
|
||||
import { Bot, createBot, createEventHandlers, startBot } from "../mod.ts";
|
||||
|
||||
// First complete non-api reliant testing.
|
||||
// Don't waste api rate limits if a early test fails.
|
||||
import "./local.ts";
|
||||
Deno.test("[Bot] - Starting Tests", async (t) => {
|
||||
const bot = createBot({
|
||||
token: TOKEN || Deno.env.get('DISCORD_TOKEN'),
|
||||
botId: 0n,
|
||||
events: createEventHandlers({
|
||||
|
||||
// API TESTING BELOW
|
||||
}),
|
||||
intents: [],
|
||||
})
|
||||
|
||||
// First initiate the connection
|
||||
import "./ws/start_bot.ts";
|
||||
import "./guilds/create_guild.ts";
|
||||
await startBot(bot as Bot);
|
||||
|
||||
// Channel tests
|
||||
import "./channels/category_children.ts";
|
||||
import "./channels/channel_overwrite_has_permission.ts";
|
||||
import "./channels/create_channel.ts";
|
||||
import "./channels/clone_channel.ts";
|
||||
import "./channels/delete_channel.ts";
|
||||
import "./channels/delete_channel_overwrite.ts";
|
||||
import "./channels/edit_channel.ts";
|
||||
import "./channels/edit_channel_overwrite.ts";
|
||||
import "./channels/get_channel.ts";
|
||||
import "./channels/get_channels.ts";
|
||||
import "./channels/get_pins.ts";
|
||||
import "./channels/is_channel_synced.ts";
|
||||
import "./channels/start_typing.ts";
|
||||
import "./channels/swap_channels.ts";
|
||||
console.log('Bot online')
|
||||
})
|
||||
|
||||
// Emojis tests
|
||||
import "./emojis/create_emoji.ts";
|
||||
import "./emojis/delete_emoji.ts";
|
||||
import "./emojis/edit_emoji.ts";
|
||||
import "./emojis/get_emoji.ts";
|
||||
import "./emojis/get_emojis.ts";
|
||||
|
||||
// Invites tests
|
||||
import "./invites/create_invite.ts";
|
||||
import "./invites/delete_invite.ts";
|
||||
import "./invites/get_channel_invites.ts";
|
||||
import "./invites/get_invite.ts";
|
||||
import "./invites/get_invites.ts";
|
||||
|
||||
// Messages tests
|
||||
import "./messages/add_reaction.ts";
|
||||
import "./messages/add_reactions.ts";
|
||||
import "./messages/remove_all_reactions.ts";
|
||||
import "./messages/remove_reaction.ts";
|
||||
import "./messages/remove_reaction_emoji.ts";
|
||||
import "./messages/create_message.ts";
|
||||
import "./messages/delete_message.ts";
|
||||
import "./messages/delete_messages.ts";
|
||||
import "./messages/edit_message.ts";
|
||||
import "./messages/get_message.ts";
|
||||
import "./messages/get_messages.ts";
|
||||
import "./messages/get_reactions.ts";
|
||||
import "./messages/pin_message.ts";
|
||||
import "./messages/unpin_message.ts";
|
||||
|
||||
// Roles tests
|
||||
import "./roles/add_role.ts";
|
||||
import "./roles/create_role.ts";
|
||||
import "./roles/delete_role.ts";
|
||||
import "./roles/edit_role.ts";
|
||||
import "./roles/remove_role.ts";
|
||||
|
||||
// Members tests
|
||||
import "./members/search_members.ts";
|
||||
|
||||
// Discoveries tests
|
||||
import "./discoveries/get_discovery_categories.ts";
|
||||
import "./discoveries/valid_discovery_term.ts";
|
||||
|
||||
// Final cleanup
|
||||
import "./guilds/delete_guild.ts";
|
||||
import "./ws/ws_close.ts";
|
||||
|
||||
import { cache } from "../src/cache.ts";
|
||||
import { delay } from "../src/util/utils.ts";
|
||||
if (import.meta.main) {
|
||||
// clear all the sweeper intervals
|
||||
for (const c of Object.values(cache)) {
|
||||
if (!(c instanceof Map)) continue;
|
||||
|
||||
c.stopSweeper();
|
||||
console.log("Cleaned");
|
||||
}
|
||||
|
||||
await delay(3000);
|
||||
}
|
||||
// // THE ORDER OF THE IMPORTS IN THIS FILE MATTER!
|
||||
// // DO NOT MOVE THEM UNLESS YOU KNOW WHAT YOUR DOING!
|
||||
|
||||
// // First complete non-api reliant testing.
|
||||
// // Don't waste api rate limits if a early test fails.
|
||||
// // import "./local.ts";
|
||||
|
||||
// // API TESTING BELOW
|
||||
|
||||
// // First initiate the connection
|
||||
// import "./ws/start_bot.ts";
|
||||
// import "./guilds/create_guild.ts";
|
||||
|
||||
// // Channel tests
|
||||
// import "./channels/category_children.ts";
|
||||
// import "./channels/channel_overwrite_has_permission.ts";
|
||||
// import "./channels/create_channel.ts";
|
||||
// import "./channels/clone_channel.ts";
|
||||
// import "./channels/delete_channel.ts";
|
||||
// import "./channels/delete_channel_overwrite.ts";
|
||||
// import "./channels/edit_channel.ts";
|
||||
// import "./channels/edit_channel_overwrite.ts";
|
||||
// import "./channels/get_channel.ts";
|
||||
// import "./channels/get_channels.ts";
|
||||
// import "./channels/get_pins.ts";
|
||||
// import "./channels/is_channel_synced.ts";
|
||||
// import "./channels/start_typing.ts";
|
||||
// import "./channels/swap_channels.ts";
|
||||
|
||||
// // Emojis tests
|
||||
// import "./emojis/create_emoji.ts";
|
||||
// import "./emojis/delete_emoji.ts";
|
||||
// import "./emojis/edit_emoji.ts";
|
||||
// import "./emojis/get_emoji.ts";
|
||||
// import "./emojis/get_emojis.ts";
|
||||
|
||||
// // Invites tests
|
||||
// import "./invites/create_invite.ts";
|
||||
// import "./invites/delete_invite.ts";
|
||||
// import "./invites/get_channel_invites.ts";
|
||||
// import "./invites/get_invite.ts";
|
||||
// import "./invites/get_invites.ts";
|
||||
|
||||
// // Messages tests
|
||||
// import "./messages/add_reaction.ts";
|
||||
// import "./messages/add_reactions.ts";
|
||||
// import "./messages/remove_all_reactions.ts";
|
||||
// import "./messages/remove_reaction.ts";
|
||||
// import "./messages/remove_reaction_emoji.ts";
|
||||
// import "./messages/create_message.ts";
|
||||
// import "./messages/delete_message.ts";
|
||||
// import "./messages/delete_messages.ts";
|
||||
// import "./messages/edit_message.ts";
|
||||
// import "./messages/get_message.ts";
|
||||
// import "./messages/get_messages.ts";
|
||||
// import "./messages/get_reactions.ts";
|
||||
// import "./messages/pin_message.ts";
|
||||
// import "./messages/unpin_message.ts";
|
||||
|
||||
// // Roles tests
|
||||
// import "./roles/add_role.ts";
|
||||
// import "./roles/create_role.ts";
|
||||
// import "./roles/delete_role.ts";
|
||||
// import "./roles/edit_role.ts";
|
||||
// import "./roles/remove_role.ts";
|
||||
|
||||
// // Members tests
|
||||
// import "./members/search_members.ts";
|
||||
|
||||
// // Discoveries tests
|
||||
// import "./discoveries/get_discovery_categories.ts";
|
||||
// import "./discoveries/valid_discovery_term.ts";
|
||||
|
||||
// // Final cleanup
|
||||
// import "./guilds/delete_guild.ts";
|
||||
// import "./ws/ws_close.ts";
|
||||
|
||||
// import { cache } from "../src/cache.ts";
|
||||
// import { delay } from "../src/util/utils.ts";
|
||||
// if (import.meta.main) {
|
||||
// // clear all the sweeper intervals
|
||||
// for (const c of Object.values(cache)) {
|
||||
// if (!(c instanceof Map)) continue;
|
||||
|
||||
// c.stopSweeper();
|
||||
// console.log("Cleaned");
|
||||
// }
|
||||
|
||||
// await delay(3000);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user