import type { BaseTokenResolution } from "openclaw/plugin-sdk/channel-contract"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/routing"; import { resolveAccountEntry } from "openclaw/plugin-sdk/routing"; import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input"; export type DiscordTokenSource = "env" | "config" | "none"; export type DiscordTokenResolution = BaseTokenResolution & { source: DiscordTokenSource; }; export function normalizeDiscordToken(raw: unknown, path: string): string | undefined { const trimmed = normalizeResolvedSecretInputString({ value: raw, path }); if (!trimmed) { return undefined; } return trimmed.replace(/^Bot\s+/i, ""); } export function resolveDiscordToken( cfg?: OpenClawConfig, opts: { accountId?: string | null; envToken?: string | null } = {}, ): DiscordTokenResolution { const accountId = normalizeAccountId(opts.accountId); const discordCfg = cfg?.channels?.discord; const accountCfg = resolveAccountEntry(discordCfg?.accounts, accountId); const hasAccountToken = Boolean( accountCfg && Object.prototype.hasOwnProperty.call(accountCfg as Record, "token"), ); const accountToken = normalizeDiscordToken( (accountCfg as { token?: unknown } | undefined)?.token ?? undefined, `channels.discord.accounts.${accountId}.token`, ); if (accountToken) { return { token: accountToken, source: "config" }; } if (hasAccountToken) { return { token: "", source: "none" }; } const configToken = normalizeDiscordToken( discordCfg?.token ?? undefined, "channels.discord.token", ); if (configToken) { return { token: configToken, source: "config" }; } const allowEnv = accountId === DEFAULT_ACCOUNT_ID; const envToken = allowEnv ? normalizeDiscordToken(opts.envToken ?? process.env.DISCORD_BOT_TOKEN, "DISCORD_BOT_TOKEN") : undefined; if (envToken) { return { token: envToken, source: "env" }; } return { token: "", source: "none" }; }