import type { BotConfig } from "@hanzo/bot/plugin-sdk/bluebubbles"; import { DEFAULT_ACCOUNT_ID, normalizeAccountId, normalizeOptionalAccountId, } from "@hanzo/bot/plugin-sdk/account-id"; import { hasConfiguredSecretInput, normalizeSecretInputString } from "./secret-input.js"; import { normalizeBlueBubblesServerUrl, type BlueBubblesAccountConfig } from "./types.js"; export type ResolvedBlueBubblesAccount = { accountId: string; enabled: boolean; name?: string; config: BlueBubblesAccountConfig; configured: boolean; baseUrl?: string; }; function listConfiguredAccountIds(cfg: BotConfig): string[] { const accounts = cfg.channels?.bluebubbles?.accounts; if (!accounts || typeof accounts !== "object") { return []; } return Object.keys(accounts).filter(Boolean); } export function listBlueBubblesAccountIds(cfg: BotConfig): string[] { const ids = listConfiguredAccountIds(cfg); if (ids.length === 0) { return [DEFAULT_ACCOUNT_ID]; } return ids.toSorted((a, b) => a.localeCompare(b)); } export function resolveDefaultBlueBubblesAccountId(cfg: BotConfig): string { const preferred = normalizeOptionalAccountId(cfg.channels?.bluebubbles?.defaultAccount); if ( preferred && listBlueBubblesAccountIds(cfg).some((accountId) => normalizeAccountId(accountId) === preferred) ) { return preferred; } const ids = listBlueBubblesAccountIds(cfg); if (ids.includes(DEFAULT_ACCOUNT_ID)) { return DEFAULT_ACCOUNT_ID; } return ids[0] ?? DEFAULT_ACCOUNT_ID; } function resolveAccountConfig( cfg: BotConfig, accountId: string, ): BlueBubblesAccountConfig | undefined { const accounts = cfg.channels?.bluebubbles?.accounts; if (!accounts || typeof accounts !== "object") { return undefined; } return accounts[accountId] as BlueBubblesAccountConfig | undefined; } function mergeBlueBubblesAccountConfig( cfg: BotConfig, accountId: string, ): BlueBubblesAccountConfig { const base = (cfg.channels?.bluebubbles ?? {}) as BlueBubblesAccountConfig & { accounts?: unknown; defaultAccount?: unknown; }; const { accounts: _ignored, defaultAccount: _ignoredDefaultAccount, ...rest } = base; const account = resolveAccountConfig(cfg, accountId) ?? {}; const chunkMode = account.chunkMode ?? rest.chunkMode ?? "length"; return { ...rest, ...account, chunkMode }; } export function resolveBlueBubblesAccount(params: { cfg: BotConfig; accountId?: string | null; }): ResolvedBlueBubblesAccount { const accountId = normalizeAccountId(params.accountId); const baseEnabled = params.cfg.channels?.bluebubbles?.enabled; const merged = mergeBlueBubblesAccountConfig(params.cfg, accountId); const accountEnabled = merged.enabled !== false; const serverUrl = normalizeSecretInputString(merged.serverUrl); const password = normalizeSecretInputString(merged.password); const configured = Boolean(serverUrl && hasConfiguredSecretInput(merged.password)); const baseUrl = serverUrl ? normalizeBlueBubblesServerUrl(serverUrl) : undefined; return { accountId, enabled: baseEnabled !== false && accountEnabled, name: merged.name?.trim() || undefined, config: merged, configured, baseUrl, }; } export function listEnabledBlueBubblesAccounts(cfg: BotConfig): ResolvedBlueBubblesAccount[] { return listBlueBubblesAccountIds(cfg) .map((accountId) => resolveBlueBubblesAccount({ cfg, accountId })) .filter((account) => account.enabled); }