diff --git a/src/discordClientOptions.ts b/src/discordClientOptions.ts new file mode 100644 index 0000000..43be8b4 --- /dev/null +++ b/src/discordClientOptions.ts @@ -0,0 +1,21 @@ +import { type ClientOptions, Options } from "discord.js-selfbot-v13"; + +export function createDiscordClientOptions(): ClientOptions { + return { + makeCache: Options.cacheWithLimits({ + ...Options.defaultMakeCacheSettings, + MessageManager: 25, + ReactionManager: 0, + ReactionUserManager: 0, + PresenceManager: 0, + }), + partials: ["USER", "CHANNEL", "GUILD_MEMBER", "MESSAGE"], + sweepers: { + messages: { interval: 300, lifetime: 600 }, + threads: { interval: 3600, lifetime: 14400 }, + }, + restRequestTimeout: 15_000, + retryLimit: 2, + restGlobalRateLimit: 45, + }; +} diff --git a/src/index.ts b/src/index.ts index fd60a60..a839bb7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,7 @@ import "dotenv/config"; import { Client } from "discord.js-selfbot-v13"; import { config } from "./config"; import { closeDatabase, initializeDatabase } from "./database/drizzle"; +import { createDiscordClientOptions } from "./discordClientOptions"; import { createChildLogger } from "./logger"; import { startPendingAIAnalysisWorker } from "./moderation/aiAnalyzer"; import { syncBacklogMessages } from "./moderation/backlogSync"; @@ -22,7 +23,7 @@ logger.info( ); logger.info("Creating Discord client"); -const client = new Client(); +const client = new Client(createDiscordClientOptions()); const voiceController = new VoiceController(client); let isShuttingDown = false; diff --git a/tests/vendor/requestHandlerBackoff.test.ts b/tests/vendor/requestHandlerBackoff.test.ts new file mode 100644 index 0000000..20d25fe --- /dev/null +++ b/tests/vendor/requestHandlerBackoff.test.ts @@ -0,0 +1,15 @@ +import { describe, expect, it } from "vitest"; + +const { calculateRetryDelay } = await import( + "../../vendor/discord.js-selfbot-v13/src/rest/RequestHandler.js" +); + +describe("calculateRetryDelay", () => { + it("increases exponentially and applies bounded jitter", () => { + expect(calculateRetryDelay(1, () => 0)).toBe(250); + expect(calculateRetryDelay(2, () => 0)).toBe(500); + expect(calculateRetryDelay(3, () => 0)).toBe(1000); + expect(calculateRetryDelay(10, () => 0)).toBe(5000); + expect(calculateRetryDelay(1, () => 0.999)).toBe(499); + }); +}); diff --git a/tests/vendor/selfbotClientOptions.test.ts b/tests/vendor/selfbotClientOptions.test.ts new file mode 100644 index 0000000..eb1cf8b --- /dev/null +++ b/tests/vendor/selfbotClientOptions.test.ts @@ -0,0 +1,22 @@ +import { describe, expect, it } from "vitest"; +import { createDiscordClientOptions } from "../../src/discordClientOptions"; + +describe("createDiscordClientOptions", () => { + it("uses low-memory message cache and active sweepers", () => { + const options = createDiscordClientOptions(); + + expect(options.restRequestTimeout).toBe(15_000); + expect(options.retryLimit).toBe(2); + expect(options.restGlobalRateLimit).toBe(45); + expect(options.sweepers).toEqual({ + messages: { interval: 300, lifetime: 600 }, + threads: { interval: 3600, lifetime: 14400 }, + }); + expect(options.partials).toEqual([ + "USER", + "CHANNEL", + "GUILD_MEMBER", + "MESSAGE", + ]); + }); +}); diff --git a/vendor/discord.js-selfbot-v13 b/vendor/discord.js-selfbot-v13 index 66e2126..d011eed 160000 --- a/vendor/discord.js-selfbot-v13 +++ b/vendor/discord.js-selfbot-v13 @@ -1 +1 @@ -Subproject commit 66e212677c304bbe7420eff4090ffc86ef832d29 +Subproject commit d011eed711a39192ea8caddd02e81fa63a34d5bb