mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-22 22:18:13 +00:00
Matrix: normalize legacy account selection
This commit is contained in:
60
src/infra/matrix-account-selection.test.ts
Normal file
60
src/infra/matrix-account-selection.test.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
|
import {
|
||||||
|
findMatrixAccountEntry,
|
||||||
|
resolveConfiguredMatrixAccountIds,
|
||||||
|
resolveMatrixDefaultOrOnlyAccountId,
|
||||||
|
} from "./matrix-account-selection.js";
|
||||||
|
|
||||||
|
describe("matrix account selection", () => {
|
||||||
|
it("resolves configured account ids from non-canonical account keys", () => {
|
||||||
|
const cfg: OpenClawConfig = {
|
||||||
|
channels: {
|
||||||
|
matrix: {
|
||||||
|
accounts: {
|
||||||
|
"Team Ops": { homeserver: "https://matrix.example.org" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(resolveConfiguredMatrixAccountIds(cfg)).toEqual(["team-ops"]);
|
||||||
|
expect(resolveMatrixDefaultOrOnlyAccountId(cfg)).toBe("team-ops");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("matches the default account against normalized Matrix account keys", () => {
|
||||||
|
const cfg: OpenClawConfig = {
|
||||||
|
channels: {
|
||||||
|
matrix: {
|
||||||
|
defaultAccount: "Team Ops",
|
||||||
|
accounts: {
|
||||||
|
"Ops Bot": { homeserver: "https://matrix.example.org" },
|
||||||
|
"Team Ops": { homeserver: "https://matrix.example.org" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(resolveMatrixDefaultOrOnlyAccountId(cfg)).toBe("team-ops");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("finds the raw Matrix account entry by normalized account id", () => {
|
||||||
|
const cfg: OpenClawConfig = {
|
||||||
|
channels: {
|
||||||
|
matrix: {
|
||||||
|
accounts: {
|
||||||
|
"Team Ops": {
|
||||||
|
homeserver: "https://matrix.example.org",
|
||||||
|
userId: "@ops:example.org",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(findMatrixAccountEntry(cfg, "team-ops")).toEqual({
|
||||||
|
homeserver: "https://matrix.example.org",
|
||||||
|
userId: "@ops:example.org",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -13,6 +13,30 @@ export function resolveMatrixChannelConfig(cfg: OpenClawConfig): Record<string,
|
|||||||
return isRecord(cfg.channels?.matrix) ? cfg.channels.matrix : null;
|
return isRecord(cfg.channels?.matrix) ? cfg.channels.matrix : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function findMatrixAccountEntry(
|
||||||
|
cfg: OpenClawConfig,
|
||||||
|
accountId: string,
|
||||||
|
): Record<string, unknown> | null {
|
||||||
|
const channel = resolveMatrixChannelConfig(cfg);
|
||||||
|
if (!channel) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const accounts = isRecord(channel.accounts) ? channel.accounts : null;
|
||||||
|
if (!accounts) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizedAccountId = normalizeAccountId(accountId);
|
||||||
|
for (const [rawAccountId, value] of Object.entries(accounts)) {
|
||||||
|
if (normalizeAccountId(rawAccountId) === normalizedAccountId && isRecord(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export function resolveConfiguredMatrixAccountIds(cfg: OpenClawConfig): string[] {
|
export function resolveConfiguredMatrixAccountIds(cfg: OpenClawConfig): string[] {
|
||||||
const channel = resolveMatrixChannelConfig(cfg);
|
const channel = resolveMatrixChannelConfig(cfg);
|
||||||
if (!channel) {
|
if (!channel) {
|
||||||
@@ -24,9 +48,9 @@ export function resolveConfiguredMatrixAccountIds(cfg: OpenClawConfig): string[]
|
|||||||
return [DEFAULT_ACCOUNT_ID];
|
return [DEFAULT_ACCOUNT_ID];
|
||||||
}
|
}
|
||||||
|
|
||||||
const ids = Object.keys(accounts)
|
const ids = Object.entries(accounts)
|
||||||
.map((accountId) => normalizeAccountId(accountId))
|
.filter(([, value]) => isRecord(value))
|
||||||
.filter((accountId) => accountId.length > 0 && isRecord(accounts[accountId]));
|
.map(([accountId]) => normalizeAccountId(accountId));
|
||||||
|
|
||||||
return Array.from(new Set(ids.length > 0 ? ids : [DEFAULT_ACCOUNT_ID])).toSorted((a, b) =>
|
return Array.from(new Set(ids.length > 0 ? ids : [DEFAULT_ACCOUNT_ID])).toSorted((a, b) =>
|
||||||
a.localeCompare(b),
|
a.localeCompare(b),
|
||||||
@@ -39,18 +63,17 @@ export function resolveMatrixDefaultOrOnlyAccountId(cfg: OpenClawConfig): string
|
|||||||
return DEFAULT_ACCOUNT_ID;
|
return DEFAULT_ACCOUNT_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
const accounts = isRecord(channel.accounts) ? channel.accounts : null;
|
|
||||||
const configuredDefault = normalizeOptionalAccountId(
|
const configuredDefault = normalizeOptionalAccountId(
|
||||||
typeof channel.defaultAccount === "string" ? channel.defaultAccount : undefined,
|
typeof channel.defaultAccount === "string" ? channel.defaultAccount : undefined,
|
||||||
);
|
);
|
||||||
if (configuredDefault && accounts && isRecord(accounts[configuredDefault])) {
|
const configuredAccountIds = resolveConfiguredMatrixAccountIds(cfg);
|
||||||
|
if (configuredDefault && configuredAccountIds.includes(configuredDefault)) {
|
||||||
return configuredDefault;
|
return configuredDefault;
|
||||||
}
|
}
|
||||||
if (accounts && isRecord(accounts[DEFAULT_ACCOUNT_ID])) {
|
if (configuredAccountIds.includes(DEFAULT_ACCOUNT_ID)) {
|
||||||
return DEFAULT_ACCOUNT_ID;
|
return DEFAULT_ACCOUNT_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
const configuredAccountIds = resolveConfiguredMatrixAccountIds(cfg);
|
|
||||||
if (configuredAccountIds.length === 1) {
|
if (configuredAccountIds.length === 1) {
|
||||||
return configuredAccountIds[0] ?? DEFAULT_ACCOUNT_ID;
|
return configuredAccountIds[0] ?? DEFAULT_ACCOUNT_ID;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import os from "node:os";
|
|||||||
import type { OpenClawConfig } from "../config/config.js";
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
import { resolveStateDir } from "../config/paths.js";
|
import { resolveStateDir } from "../config/paths.js";
|
||||||
import { normalizeAccountId } from "../routing/session-key.js";
|
import { normalizeAccountId } from "../routing/session-key.js";
|
||||||
import { resolveMatrixChannelConfig } from "./matrix-account-selection.js";
|
import { findMatrixAccountEntry, resolveMatrixChannelConfig } from "./matrix-account-selection.js";
|
||||||
import { resolveMatrixCredentialsPath } from "./matrix-storage-paths.js";
|
import { resolveMatrixCredentialsPath } from "./matrix-storage-paths.js";
|
||||||
|
|
||||||
export type MatrixStoredCredentials = {
|
export type MatrixStoredCredentials = {
|
||||||
@@ -13,10 +13,6 @@ export type MatrixStoredCredentials = {
|
|||||||
deviceId?: string;
|
deviceId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
||||||
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function clean(value: unknown): string {
|
function clean(value: unknown): string {
|
||||||
return typeof value === "string" ? value.trim() : "";
|
return typeof value === "string" ? value.trim() : "";
|
||||||
}
|
}
|
||||||
@@ -60,12 +56,7 @@ function resolveMatrixAccountConfigEntry(
|
|||||||
cfg: OpenClawConfig,
|
cfg: OpenClawConfig,
|
||||||
accountId: string,
|
accountId: string,
|
||||||
): Record<string, unknown> | null {
|
): Record<string, unknown> | null {
|
||||||
const channel = resolveMatrixChannelConfig(cfg);
|
return findMatrixAccountEntry(cfg, accountId);
|
||||||
if (!channel) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const accounts = isRecord(channel.accounts) ? channel.accounts : null;
|
|
||||||
return accounts && isRecord(accounts[accountId]) ? accounts[accountId] : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveMatrixMigrationConfigFields(params: {
|
export function resolveMatrixMigrationConfigFields(params: {
|
||||||
|
|||||||
Reference in New Issue
Block a user