refactor: dedupe discord account inspect config merge

This commit is contained in:
Peter Steinberger
2026-03-07 19:47:41 +00:00
parent 7242777d63
commit 2ee8b807f8
3 changed files with 138 additions and 21 deletions

View File

@@ -0,0 +1,126 @@
import { describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import { inspectDiscordAccount } from "./account-inspect.js";
function asConfig(value: unknown): OpenClawConfig {
return value as OpenClawConfig;
}
describe("inspectDiscordAccount", () => {
it("prefers account token over channel token and strips Bot prefix", () => {
const inspected = inspectDiscordAccount({
cfg: asConfig({
channels: {
discord: {
token: "Bot channel-token",
accounts: {
work: {
token: "Bot account-token",
},
},
},
},
}),
accountId: "work",
});
expect(inspected.token).toBe("account-token");
expect(inspected.tokenSource).toBe("config");
expect(inspected.tokenStatus).toBe("available");
expect(inspected.configured).toBe(true);
});
it("reports configured_unavailable for unresolved configured secret input", () => {
const inspected = inspectDiscordAccount({
cfg: asConfig({
channels: {
discord: {
accounts: {
work: {
token: { source: "env", id: "DISCORD_TOKEN" },
},
},
},
},
}),
accountId: "work",
});
expect(inspected.token).toBe("");
expect(inspected.tokenSource).toBe("config");
expect(inspected.tokenStatus).toBe("configured_unavailable");
expect(inspected.configured).toBe(true);
});
it("does not fall back when account token key exists but is missing", () => {
const inspected = inspectDiscordAccount({
cfg: asConfig({
channels: {
discord: {
token: "Bot channel-token",
accounts: {
work: {
token: "",
},
},
},
},
}),
accountId: "work",
});
expect(inspected.token).toBe("");
expect(inspected.tokenSource).toBe("none");
expect(inspected.tokenStatus).toBe("missing");
expect(inspected.configured).toBe(false);
});
it("falls back to channel token when account token is absent", () => {
const inspected = inspectDiscordAccount({
cfg: asConfig({
channels: {
discord: {
token: "Bot channel-token",
accounts: {
work: {},
},
},
},
}),
accountId: "work",
});
expect(inspected.token).toBe("channel-token");
expect(inspected.tokenSource).toBe("config");
expect(inspected.tokenStatus).toBe("available");
expect(inspected.configured).toBe(true);
});
it("allows env token only for default account", () => {
const defaultInspected = inspectDiscordAccount({
cfg: asConfig({}),
accountId: "default",
envToken: "Bot env-default",
});
const namedInspected = inspectDiscordAccount({
cfg: asConfig({
channels: {
discord: {
accounts: {
work: {},
},
},
},
}),
accountId: "work",
envToken: "Bot env-work",
});
expect(defaultInspected.token).toBe("env-default");
expect(defaultInspected.tokenSource).toBe("env");
expect(defaultInspected.configured).toBe(true);
expect(namedInspected.token).toBe("");
expect(namedInspected.tokenSource).toBe("none");
expect(namedInspected.configured).toBe(false);
});
});

View File

@@ -1,9 +1,12 @@
import type { OpenClawConfig } from "../config/config.js";
import type { DiscordAccountConfig } from "../config/types.discord.js";
import { hasConfiguredSecretInput, normalizeSecretInputString } from "../config/types.secrets.js";
import { resolveAccountEntry } from "../routing/account-lookup.js";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js";
import { resolveDefaultDiscordAccountId } from "./accounts.js";
import {
mergeDiscordAccountConfig,
resolveDefaultDiscordAccountId,
resolveDiscordAccountConfig,
} from "./accounts.js";
export type DiscordCredentialStatus = "available" | "configured_unavailable" | "missing";
@@ -18,21 +21,6 @@ export type InspectedDiscordAccount = {
config: DiscordAccountConfig;
};
function resolveDiscordAccountConfig(
cfg: OpenClawConfig,
accountId: string,
): DiscordAccountConfig | undefined {
return resolveAccountEntry(cfg.channels?.discord?.accounts, accountId);
}
function mergeDiscordAccountConfig(cfg: OpenClawConfig, accountId: string): DiscordAccountConfig {
const { accounts: _ignored, ...base } = (cfg.channels?.discord ?? {}) as DiscordAccountConfig & {
accounts?: unknown;
};
const account = resolveDiscordAccountConfig(cfg, accountId) ?? {};
return { ...base, ...account };
}
function inspectDiscordTokenValue(value: unknown): {
token: string;
tokenSource: "config";

View File

@@ -19,18 +19,21 @@ const { listAccountIds, resolveDefaultAccountId } = createAccountListHelpers("di
export const listDiscordAccountIds = listAccountIds;
export const resolveDefaultDiscordAccountId = resolveDefaultAccountId;
function resolveAccountConfig(
export function resolveDiscordAccountConfig(
cfg: OpenClawConfig,
accountId: string,
): DiscordAccountConfig | undefined {
return resolveAccountEntry(cfg.channels?.discord?.accounts, accountId);
}
function mergeDiscordAccountConfig(cfg: OpenClawConfig, accountId: string): DiscordAccountConfig {
export function mergeDiscordAccountConfig(
cfg: OpenClawConfig,
accountId: string,
): DiscordAccountConfig {
const { accounts: _ignored, ...base } = (cfg.channels?.discord ?? {}) as DiscordAccountConfig & {
accounts?: unknown;
};
const account = resolveAccountConfig(cfg, accountId) ?? {};
const account = resolveDiscordAccountConfig(cfg, accountId) ?? {};
return { ...base, ...account };
}
@@ -41,7 +44,7 @@ export function createDiscordActionGate(params: {
const accountId = normalizeAccountId(params.accountId);
return createAccountActionGate({
baseActions: params.cfg.channels?.discord?.actions,
accountActions: resolveAccountConfig(params.cfg, accountId)?.actions,
accountActions: resolveDiscordAccountConfig(params.cfg, accountId)?.actions,
});
}