import { RequestClient } from "@buape/carbon"; import { loadConfig } from "../../../src/config/config.js"; import { createDiscordRetryRunner, type RetryRunner } from "../../../src/infra/retry-policy.js"; import type { RetryConfig } from "../../../src/infra/retry.js"; import { normalizeAccountId } from "../../../src/routing/session-key.js"; import { mergeDiscordAccountConfig, resolveDiscordAccount, type ResolvedDiscordAccount, } from "./accounts.js"; import { normalizeDiscordToken } from "./token.js"; export type DiscordClientOpts = { cfg?: ReturnType; token?: string; accountId?: string; rest?: RequestClient; retry?: RetryConfig; verbose?: boolean; }; function resolveToken(params: { accountId: string; fallbackToken?: string }) { const fallback = normalizeDiscordToken(params.fallbackToken, "channels.discord.token"); if (!fallback) { throw new Error( `Discord bot token missing for account "${params.accountId}" (set discord.accounts.${params.accountId}.token or DISCORD_BOT_TOKEN for default).`, ); } return fallback; } function resolveRest(token: string, rest?: RequestClient) { return rest ?? new RequestClient(token); } function resolveAccountWithoutToken(params: { cfg: ReturnType; accountId?: string; }): ResolvedDiscordAccount { const accountId = normalizeAccountId(params.accountId); const merged = mergeDiscordAccountConfig(params.cfg, accountId); const baseEnabled = params.cfg.channels?.discord?.enabled !== false; const accountEnabled = merged.enabled !== false; return { accountId, enabled: baseEnabled && accountEnabled, name: merged.name?.trim() || undefined, token: "", tokenSource: "none", config: merged, }; } export function createDiscordRestClient( opts: DiscordClientOpts, cfg?: ReturnType, ) { const resolvedCfg = opts.cfg ?? cfg ?? loadConfig(); const explicitToken = normalizeDiscordToken(opts.token, "channels.discord.token"); const account = explicitToken ? resolveAccountWithoutToken({ cfg: resolvedCfg, accountId: opts.accountId }) : resolveDiscordAccount({ cfg: resolvedCfg, accountId: opts.accountId }); const token = explicitToken ?? resolveToken({ accountId: account.accountId, fallbackToken: account.token, }); const rest = resolveRest(token, opts.rest); return { token, rest, account }; } export function createDiscordClient( opts: DiscordClientOpts, cfg?: ReturnType, ): { token: string; rest: RequestClient; request: RetryRunner } { const { token, rest, account } = createDiscordRestClient(opts, opts.cfg ?? cfg); const request = createDiscordRetryRunner({ retry: opts.retry, configRetry: account.config.retry, verbose: opts.verbose, }); return { token, rest, request }; } export function resolveDiscordRest(opts: DiscordClientOpts) { return createDiscordRestClient(opts, opts.cfg).rest; }