|
| 1 | +import type { Client, ClientEvents } from "discord.js"; |
| 2 | + |
| 3 | +import { log } from "#~/helpers/observability"; |
| 4 | + |
| 5 | +// All HMR-related global state declarations |
| 6 | +declare global { |
| 7 | + var __discordListenerRegistry: |
| 8 | + | { event: string; listener: (...args: unknown[]) => void }[] |
| 9 | + | undefined; |
| 10 | + var __discordScheduledTasks: ReturnType<typeof setTimeout>[] | undefined; |
| 11 | + var __discordClientReady: boolean | undefined; |
| 12 | + var __discordLoginStarted: boolean | undefined; |
| 13 | +} |
| 14 | + |
| 15 | +// --- Login state --- |
| 16 | + |
| 17 | +export function isLoginStarted(): boolean { |
| 18 | + return globalThis.__discordLoginStarted ?? false; |
| 19 | +} |
| 20 | + |
| 21 | +export function markLoginStarted(): void { |
| 22 | + globalThis.__discordLoginStarted = true; |
| 23 | +} |
| 24 | + |
| 25 | +// --- Client ready state --- |
| 26 | + |
| 27 | +export function isClientReady(): boolean { |
| 28 | + return globalThis.__discordClientReady ?? false; |
| 29 | +} |
| 30 | + |
| 31 | +export function setClientReady(): void { |
| 32 | + globalThis.__discordClientReady = true; |
| 33 | +} |
| 34 | + |
| 35 | +// --- Scheduled tasks --- |
| 36 | + |
| 37 | +export function registerScheduledTask( |
| 38 | + timer: ReturnType<typeof setTimeout>, |
| 39 | +): void { |
| 40 | + globalThis.__discordScheduledTasks ??= []; |
| 41 | + globalThis.__discordScheduledTasks.push(timer); |
| 42 | +} |
| 43 | + |
| 44 | +export function clearScheduledTasks(): void { |
| 45 | + const tasks = globalThis.__discordScheduledTasks ?? []; |
| 46 | + if (tasks.length > 0) { |
| 47 | + log("info", "HMR", `Clearing ${tasks.length} scheduled tasks`); |
| 48 | + } |
| 49 | + for (const timer of tasks) { |
| 50 | + clearTimeout(timer); |
| 51 | + clearInterval(timer); |
| 52 | + } |
| 53 | + globalThis.__discordScheduledTasks = []; |
| 54 | +} |
| 55 | + |
| 56 | +// --- Listener registry --- |
| 57 | + |
| 58 | +/** |
| 59 | + * Register a listener with the Discord client and track it for HMR cleanup. |
| 60 | + */ |
| 61 | +export function registerListener<K extends keyof ClientEvents>( |
| 62 | + client: Client, |
| 63 | + event: K, |
| 64 | + listener: (...args: ClientEvents[K]) => void, |
| 65 | +): void { |
| 66 | + globalThis.__discordListenerRegistry ??= []; |
| 67 | + client.on(event, listener); |
| 68 | + globalThis.__discordListenerRegistry.push({ |
| 69 | + event, |
| 70 | + listener: listener as (...args: unknown[]) => void, |
| 71 | + }); |
| 72 | +} |
| 73 | + |
| 74 | +/** |
| 75 | + * Remove all tracked listeners from the client. |
| 76 | + * Call this before rebinding listeners on HMR. |
| 77 | + */ |
| 78 | +export function removeAllListeners(client: Client): void { |
| 79 | + const registry = globalThis.__discordListenerRegistry ?? []; |
| 80 | + if (registry.length > 0) { |
| 81 | + log("info", "HMR", `Removing ${registry.length} listeners for HMR`); |
| 82 | + } |
| 83 | + for (const { event, listener } of registry) { |
| 84 | + client.off(event, listener); |
| 85 | + } |
| 86 | + globalThis.__discordListenerRegistry = []; |
| 87 | +} |
| 88 | + |
| 89 | +/** |
| 90 | + * Get the count of currently registered listeners. |
| 91 | + */ |
| 92 | +export function getListenerCount(): number { |
| 93 | + return globalThis.__discordListenerRegistry?.length ?? 0; |
| 94 | +} |
0 commit comments