feat(matrix): add multi-account support
Some checks failed
CI / install-check (push) Has been cancelled
CI / checks (bunx tsc -p tsconfig.json --noEmit false, bun, build) (push) Has been cancelled
CI / checks (pnpm build, node, build) (push) Has been cancelled
CI / checks (pnpm canvas:a2ui:bundle && bunx vitest run, bun, test) (push) Has been cancelled
CI / checks (pnpm canvas:a2ui:bundle && pnpm test, node, test) (push) Has been cancelled
CI / checks (pnpm format, node, format) (push) Has been cancelled
CI / checks (pnpm lint, node, lint) (push) Has been cancelled
CI / checks (pnpm protocol:check, node, protocol) (push) Has been cancelled
CI / checks (pnpm tsgo, node, tsgo) (push) Has been cancelled
CI / secrets (push) Has been cancelled
CI / checks-windows (pnpm build, node, build) (push) Has been cancelled
CI / checks-windows (pnpm canvas:a2ui:bundle && pnpm test, node, test) (push) Has been cancelled
CI / checks-windows (pnpm lint, node, lint) (push) Has been cancelled
CI / checks-windows (pnpm protocol:check, node, protocol) (push) Has been cancelled
CI / checks-macos (pnpm test, test) (push) Has been cancelled
CI / macos-app (set -euo pipefail
for attempt in 1 2 3; do
if swift build --package-path apps/macos --configuration release; then
exit 0
fi
echo "swift build failed (attempt $attempt/3). Retrying…"
sleep $((attempt * 20))
done
exit 1
, build) (push) Has been cancelled
CI / macos-app (set -euo pipefail
for attempt in 1 2 3; do
if swift test --package-path apps/macos --parallel --enable-code-coverage --show-codecov-path; then
exit 0
fi
echo "swift test failed (attempt $attempt/3). Retrying…"
sleep $((attempt … (push) Has been cancelled
CI / macos-app (swiftlint --config .swiftlint.yml
swiftformat --lint apps/macos/Sources --config .swiftformat
, lint) (push) Has been cancelled
CI / ios (push) Has been cancelled
CI / android (./gradlew --no-daemon :app:assembleDebug, build) (push) Has been cancelled
CI / android (./gradlew --no-daemon :app:testDebugUnitTest, test) (push) Has been cancelled
Docker Release / build-amd64 (push) Has been cancelled
Docker Release / build-arm64 (push) Has been cancelled
Install Smoke / install-smoke (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Docker Release / create-manifest (push) Has been cancelled
Some checks failed
CI / install-check (push) Has been cancelled
CI / checks (bunx tsc -p tsconfig.json --noEmit false, bun, build) (push) Has been cancelled
CI / checks (pnpm build, node, build) (push) Has been cancelled
CI / checks (pnpm canvas:a2ui:bundle && bunx vitest run, bun, test) (push) Has been cancelled
CI / checks (pnpm canvas:a2ui:bundle && pnpm test, node, test) (push) Has been cancelled
CI / checks (pnpm format, node, format) (push) Has been cancelled
CI / checks (pnpm lint, node, lint) (push) Has been cancelled
CI / checks (pnpm protocol:check, node, protocol) (push) Has been cancelled
CI / checks (pnpm tsgo, node, tsgo) (push) Has been cancelled
CI / secrets (push) Has been cancelled
CI / checks-windows (pnpm build, node, build) (push) Has been cancelled
CI / checks-windows (pnpm canvas:a2ui:bundle && pnpm test, node, test) (push) Has been cancelled
CI / checks-windows (pnpm lint, node, lint) (push) Has been cancelled
CI / checks-windows (pnpm protocol:check, node, protocol) (push) Has been cancelled
CI / checks-macos (pnpm test, test) (push) Has been cancelled
CI / macos-app (set -euo pipefail
for attempt in 1 2 3; do
if swift build --package-path apps/macos --configuration release; then
exit 0
fi
echo "swift build failed (attempt $attempt/3). Retrying…"
sleep $((attempt * 20))
done
exit 1
, build) (push) Has been cancelled
CI / macos-app (set -euo pipefail
for attempt in 1 2 3; do
if swift test --package-path apps/macos --parallel --enable-code-coverage --show-codecov-path; then
exit 0
fi
echo "swift test failed (attempt $attempt/3). Retrying…"
sleep $((attempt … (push) Has been cancelled
CI / macos-app (swiftlint --config .swiftlint.yml
swiftformat --lint apps/macos/Sources --config .swiftformat
, lint) (push) Has been cancelled
CI / ios (push) Has been cancelled
CI / android (./gradlew --no-daemon :app:assembleDebug, build) (push) Has been cancelled
CI / android (./gradlew --no-daemon :app:testDebugUnitTest, test) (push) Has been cancelled
Docker Release / build-amd64 (push) Has been cancelled
Docker Release / build-arm64 (push) Has been cancelled
Install Smoke / install-smoke (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Docker Release / create-manifest (push) Has been cancelled
- Add accounts field to MatrixConfig type for per-account configuration - Update listMatrixAccountIds() to enumerate accounts from config + bindings - Add mergeMatrixAccountConfig() to merge base config with account overrides - Update resolveMatrixAuth() to accept accountId parameter - Pass accountId through monitor to use correct credentials per account This enables running multiple Matrix bot accounts simultaneously, each connecting to different rooms with isolated sessions.
This commit is contained in:
parent
247fab47ca
commit
6ac04375e6
4 changed files with 221 additions and 56 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk";
|
||||
import type { CoreConfig, MatrixConfig } from "../types.js";
|
||||
import type { CoreConfig, MatrixAccountConfig, MatrixConfig } from "../types.js";
|
||||
import { resolveMatrixConfig } from "./client.js";
|
||||
import { credentialsMatchConfig, loadMatrixCredentials } from "./credentials.js";
|
||||
|
||||
|
|
@ -10,11 +10,53 @@ export type ResolvedMatrixAccount = {
|
|||
configured: boolean;
|
||||
homeserver?: string;
|
||||
userId?: string;
|
||||
config: MatrixConfig;
|
||||
accessToken?: string;
|
||||
config: MatrixAccountConfig;
|
||||
};
|
||||
|
||||
export function listMatrixAccountIds(_cfg: CoreConfig): string[] {
|
||||
return [DEFAULT_ACCOUNT_ID];
|
||||
/**
|
||||
* List account IDs explicitly configured in channels.matrix.accounts
|
||||
*/
|
||||
function listConfiguredAccountIds(cfg: CoreConfig): string[] {
|
||||
const accounts = cfg.channels?.matrix?.accounts;
|
||||
if (!accounts || typeof accounts !== "object") {
|
||||
return [];
|
||||
}
|
||||
const ids = new Set<string>();
|
||||
for (const key of Object.keys(accounts)) {
|
||||
if (!key) continue;
|
||||
ids.add(normalizeAccountId(key));
|
||||
}
|
||||
return [...ids];
|
||||
}
|
||||
|
||||
/**
|
||||
* List account IDs referenced in bindings for matrix channel
|
||||
*/
|
||||
function listBoundAccountIds(cfg: CoreConfig): string[] {
|
||||
const bindings = cfg.bindings;
|
||||
if (!Array.isArray(bindings)) return [];
|
||||
const ids = new Set<string>();
|
||||
for (const binding of bindings) {
|
||||
if (binding.match?.channel === "matrix" && binding.match?.accountId) {
|
||||
ids.add(normalizeAccountId(binding.match.accountId));
|
||||
}
|
||||
}
|
||||
return [...ids];
|
||||
}
|
||||
|
||||
/**
|
||||
* List all Matrix account IDs (configured + bound)
|
||||
*/
|
||||
export function listMatrixAccountIds(cfg: CoreConfig): string[] {
|
||||
const ids = Array.from(
|
||||
new Set([
|
||||
DEFAULT_ACCOUNT_ID,
|
||||
...listConfiguredAccountIds(cfg),
|
||||
...listBoundAccountIds(cfg),
|
||||
]),
|
||||
);
|
||||
return ids.toSorted((a, b) => a.localeCompare(b));
|
||||
}
|
||||
|
||||
export function resolveDefaultMatrixAccountId(cfg: CoreConfig): string {
|
||||
|
|
@ -23,41 +65,100 @@ export function resolveDefaultMatrixAccountId(cfg: CoreConfig): string {
|
|||
return ids[0] ?? DEFAULT_ACCOUNT_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get account-specific config from channels.matrix.accounts[accountId]
|
||||
*/
|
||||
function resolveAccountConfig(
|
||||
cfg: CoreConfig,
|
||||
accountId: string,
|
||||
): MatrixAccountConfig | undefined {
|
||||
const accounts = cfg.channels?.matrix?.accounts;
|
||||
if (!accounts || typeof accounts !== "object") {
|
||||
return undefined;
|
||||
}
|
||||
const direct = accounts[accountId] as MatrixAccountConfig | undefined;
|
||||
if (direct) return direct;
|
||||
|
||||
const normalized = normalizeAccountId(accountId);
|
||||
const matchKey = Object.keys(accounts).find(
|
||||
(key) => normalizeAccountId(key) === normalized
|
||||
);
|
||||
return matchKey ? (accounts[matchKey] as MatrixAccountConfig | undefined) : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge base matrix config with account-specific overrides
|
||||
*/
|
||||
function mergeMatrixAccountConfig(cfg: CoreConfig, accountId: string): MatrixAccountConfig {
|
||||
const base = cfg.channels?.matrix ?? {};
|
||||
// Extract base config without 'accounts' key
|
||||
const { accounts: _ignored, ...baseConfig } = base as MatrixConfig;
|
||||
const accountConfig = resolveAccountConfig(cfg, accountId) ?? {};
|
||||
|
||||
// Account config overrides base config
|
||||
return { ...baseConfig, ...accountConfig };
|
||||
}
|
||||
|
||||
export function resolveMatrixAccount(params: {
|
||||
cfg: CoreConfig;
|
||||
accountId?: string | null;
|
||||
}): ResolvedMatrixAccount {
|
||||
const accountId = normalizeAccountId(params.accountId);
|
||||
const base = (params.cfg.channels?.matrix ?? {}) as MatrixConfig;
|
||||
const enabled = base.enabled !== false;
|
||||
const resolved = resolveMatrixConfig(params.cfg, process.env);
|
||||
const hasHomeserver = Boolean(resolved.homeserver);
|
||||
const hasUserId = Boolean(resolved.userId);
|
||||
const hasAccessToken = Boolean(resolved.accessToken);
|
||||
const hasPassword = Boolean(resolved.password);
|
||||
const merged = mergeMatrixAccountConfig(params.cfg, accountId);
|
||||
|
||||
// Check if this is a non-default account - use account-specific auth
|
||||
const isDefaultAccount = accountId === DEFAULT_ACCOUNT_ID || accountId === "default";
|
||||
|
||||
// For non-default accounts, use account-specific credentials
|
||||
// For default account, use base config or env
|
||||
let homeserver = merged.homeserver;
|
||||
let userId = merged.userId;
|
||||
let accessToken = merged.accessToken;
|
||||
|
||||
if (isDefaultAccount) {
|
||||
// Default account can fall back to env vars
|
||||
const resolved = resolveMatrixConfig(params.cfg, process.env);
|
||||
homeserver = homeserver || resolved.homeserver;
|
||||
userId = userId || resolved.userId;
|
||||
accessToken = accessToken || resolved.accessToken;
|
||||
}
|
||||
|
||||
const baseEnabled = params.cfg.channels?.matrix?.enabled !== false;
|
||||
const accountEnabled = merged.enabled !== false;
|
||||
const enabled = baseEnabled && accountEnabled;
|
||||
|
||||
const hasHomeserver = Boolean(homeserver);
|
||||
const hasAccessToken = Boolean(accessToken);
|
||||
const hasPassword = Boolean(merged.password);
|
||||
const hasUserId = Boolean(userId);
|
||||
const hasPasswordAuth = hasUserId && hasPassword;
|
||||
const stored = loadMatrixCredentials(process.env);
|
||||
|
||||
// Check for stored credentials (only for default account)
|
||||
const stored = isDefaultAccount ? loadMatrixCredentials(process.env) : null;
|
||||
const hasStored =
|
||||
stored && resolved.homeserver
|
||||
stored && homeserver
|
||||
? credentialsMatchConfig(stored, {
|
||||
homeserver: resolved.homeserver,
|
||||
userId: resolved.userId || "",
|
||||
homeserver: homeserver,
|
||||
userId: userId || "",
|
||||
})
|
||||
: false;
|
||||
|
||||
const configured = hasHomeserver && (hasAccessToken || hasPasswordAuth || Boolean(hasStored));
|
||||
|
||||
return {
|
||||
accountId,
|
||||
enabled,
|
||||
name: base.name?.trim() || undefined,
|
||||
name: merged.name?.trim() || undefined,
|
||||
configured,
|
||||
homeserver: resolved.homeserver || undefined,
|
||||
userId: resolved.userId || undefined,
|
||||
config: base,
|
||||
homeserver: homeserver || undefined,
|
||||
userId: userId || undefined,
|
||||
accessToken: accessToken || undefined,
|
||||
config: merged,
|
||||
};
|
||||
}
|
||||
|
||||
export function listEnabledMatrixAccounts(cfg: CoreConfig): ResolvedMatrixAccount[] {
|
||||
return listMatrixAccountIds(cfg)
|
||||
.map((accountId) => resolveMatrixAccount({ cfg, accountId }))
|
||||
.filter((account) => account.enabled);
|
||||
.filter((account) => account.enabled && account.configured);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { MatrixClient } from "@vector-im/matrix-bot-sdk";
|
||||
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk";
|
||||
|
||||
import type { CoreConfig } from "../types.js";
|
||||
import type { CoreConfig, MatrixAccountConfig, MatrixConfig } from "../types.js";
|
||||
import { getMatrixRuntime } from "../../runtime.js";
|
||||
import { ensureMatrixSdkLoggingConfigured } from "./logging.js";
|
||||
import type { MatrixAuth, MatrixResolvedConfig } from "./types.js";
|
||||
|
|
@ -9,23 +10,60 @@ function clean(value?: string): string {
|
|||
return value?.trim() ?? "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get account-specific config from channels.matrix.accounts[accountId]
|
||||
*/
|
||||
function resolveAccountConfig(
|
||||
cfg: CoreConfig,
|
||||
accountId: string,
|
||||
): MatrixAccountConfig | undefined {
|
||||
const accounts = cfg.channels?.matrix?.accounts;
|
||||
if (!accounts || typeof accounts !== "object") {
|
||||
return undefined;
|
||||
}
|
||||
const direct = accounts[accountId] as MatrixAccountConfig | undefined;
|
||||
if (direct) return direct;
|
||||
|
||||
const normalized = normalizeAccountId(accountId);
|
||||
const matchKey = Object.keys(accounts).find(
|
||||
(key) => normalizeAccountId(key) === normalized
|
||||
);
|
||||
return matchKey ? (accounts[matchKey] as MatrixAccountConfig | undefined) : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge base matrix config with account-specific overrides
|
||||
*/
|
||||
function mergeMatrixAccountConfig(cfg: CoreConfig, accountId: string): MatrixAccountConfig {
|
||||
const base = cfg.channels?.matrix ?? {};
|
||||
const { accounts: _ignored, ...baseConfig } = base as MatrixConfig;
|
||||
const accountConfig = resolveAccountConfig(cfg, accountId) ?? {};
|
||||
return { ...baseConfig, ...accountConfig };
|
||||
}
|
||||
|
||||
export function resolveMatrixConfig(
|
||||
cfg: CoreConfig = getMatrixRuntime().config.loadConfig() as CoreConfig,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
accountId?: string,
|
||||
): MatrixResolvedConfig {
|
||||
const matrix = cfg.channels?.matrix ?? {};
|
||||
const homeserver = clean(matrix.homeserver) || clean(env.MATRIX_HOMESERVER);
|
||||
const userId = clean(matrix.userId) || clean(env.MATRIX_USER_ID);
|
||||
const accessToken =
|
||||
clean(matrix.accessToken) || clean(env.MATRIX_ACCESS_TOKEN) || undefined;
|
||||
const password = clean(matrix.password) || clean(env.MATRIX_PASSWORD) || undefined;
|
||||
const deviceName =
|
||||
clean(matrix.deviceName) || clean(env.MATRIX_DEVICE_NAME) || undefined;
|
||||
const normalizedAccountId = normalizeAccountId(accountId);
|
||||
const isDefaultAccount = normalizedAccountId === DEFAULT_ACCOUNT_ID || normalizedAccountId === "default";
|
||||
|
||||
// Get merged config for this account
|
||||
const merged = mergeMatrixAccountConfig(cfg, normalizedAccountId);
|
||||
|
||||
// For default account, allow env var fallbacks
|
||||
const homeserver = clean(merged.homeserver) || (isDefaultAccount ? clean(env.MATRIX_HOMESERVER) : "");
|
||||
const userId = clean(merged.userId) || (isDefaultAccount ? clean(env.MATRIX_USER_ID) : "");
|
||||
const accessToken = clean(merged.accessToken) || (isDefaultAccount ? clean(env.MATRIX_ACCESS_TOKEN) : "") || undefined;
|
||||
const password = clean(merged.password) || (isDefaultAccount ? clean(env.MATRIX_PASSWORD) : "") || undefined;
|
||||
const deviceName = clean(merged.deviceName) || (isDefaultAccount ? clean(env.MATRIX_DEVICE_NAME) : "") || undefined;
|
||||
const initialSyncLimit =
|
||||
typeof matrix.initialSyncLimit === "number"
|
||||
? Math.max(0, Math.floor(matrix.initialSyncLimit))
|
||||
typeof merged.initialSyncLimit === "number"
|
||||
? Math.max(0, Math.floor(merged.initialSyncLimit))
|
||||
: undefined;
|
||||
const encryption = matrix.encryption ?? false;
|
||||
const encryption = merged.encryption ?? false;
|
||||
|
||||
return {
|
||||
homeserver,
|
||||
userId,
|
||||
|
|
@ -40,14 +78,21 @@ export function resolveMatrixConfig(
|
|||
export async function resolveMatrixAuth(params?: {
|
||||
cfg?: CoreConfig;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
accountId?: string;
|
||||
}): Promise<MatrixAuth> {
|
||||
const cfg = params?.cfg ?? (getMatrixRuntime().config.loadConfig() as CoreConfig);
|
||||
const env = params?.env ?? process.env;
|
||||
const resolved = resolveMatrixConfig(cfg, env);
|
||||
const accountId = params?.accountId;
|
||||
const resolved = resolveMatrixConfig(cfg, env, accountId);
|
||||
|
||||
if (!resolved.homeserver) {
|
||||
throw new Error("Matrix homeserver is required (matrix.homeserver)");
|
||||
throw new Error(`Matrix homeserver is required for account ${accountId ?? "default"} (matrix.homeserver)`);
|
||||
}
|
||||
|
||||
const normalizedAccountId = normalizeAccountId(accountId);
|
||||
const isDefaultAccount = normalizedAccountId === DEFAULT_ACCOUNT_ID || normalizedAccountId === "default";
|
||||
|
||||
// Only use cached credentials for default account
|
||||
const {
|
||||
loadMatrixCredentials,
|
||||
saveMatrixCredentials,
|
||||
|
|
@ -55,7 +100,7 @@ export async function resolveMatrixAuth(params?: {
|
|||
touchMatrixCredentials,
|
||||
} = await import("../credentials.js");
|
||||
|
||||
const cached = loadMatrixCredentials(env);
|
||||
const cached = isDefaultAccount ? loadMatrixCredentials(env) : null;
|
||||
const cachedCredentials =
|
||||
cached &&
|
||||
credentialsMatchConfig(cached, {
|
||||
|
|
@ -74,13 +119,15 @@ export async function resolveMatrixAuth(params?: {
|
|||
const tempClient = new MatrixClient(resolved.homeserver, resolved.accessToken);
|
||||
const whoami = await tempClient.getUserId();
|
||||
userId = whoami;
|
||||
// Save the credentials with the fetched userId
|
||||
saveMatrixCredentials({
|
||||
homeserver: resolved.homeserver,
|
||||
userId,
|
||||
accessToken: resolved.accessToken,
|
||||
});
|
||||
} else if (cachedCredentials && cachedCredentials.accessToken === resolved.accessToken) {
|
||||
// Only save credentials for default account
|
||||
if (isDefaultAccount) {
|
||||
saveMatrixCredentials({
|
||||
homeserver: resolved.homeserver,
|
||||
userId,
|
||||
accessToken: resolved.accessToken,
|
||||
});
|
||||
}
|
||||
} else if (isDefaultAccount && cachedCredentials && cachedCredentials.accessToken === resolved.accessToken) {
|
||||
touchMatrixCredentials(env);
|
||||
}
|
||||
return {
|
||||
|
|
@ -93,7 +140,8 @@ export async function resolveMatrixAuth(params?: {
|
|||
};
|
||||
}
|
||||
|
||||
if (cachedCredentials) {
|
||||
// Try cached credentials (only for default account)
|
||||
if (isDefaultAccount && cachedCredentials) {
|
||||
touchMatrixCredentials(env);
|
||||
return {
|
||||
homeserver: cachedCredentials.homeserver,
|
||||
|
|
@ -107,13 +155,13 @@ export async function resolveMatrixAuth(params?: {
|
|||
|
||||
if (!resolved.userId) {
|
||||
throw new Error(
|
||||
"Matrix userId is required when no access token is configured (matrix.userId)",
|
||||
`Matrix userId is required for account ${accountId ?? "default"} when no access token is configured`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!resolved.password) {
|
||||
throw new Error(
|
||||
"Matrix password is required when no access token is configured (matrix.password)",
|
||||
`Matrix password is required for account ${accountId ?? "default"} when no access token is configured`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +179,7 @@ export async function resolveMatrixAuth(params?: {
|
|||
|
||||
if (!loginResponse.ok) {
|
||||
const errorText = await loginResponse.text();
|
||||
throw new Error(`Matrix login failed: ${errorText}`);
|
||||
throw new Error(`Matrix login failed for account ${accountId ?? "default"}: ${errorText}`);
|
||||
}
|
||||
|
||||
const login = (await loginResponse.json()) as {
|
||||
|
|
@ -142,7 +190,7 @@ export async function resolveMatrixAuth(params?: {
|
|||
|
||||
const accessToken = login.access_token?.trim();
|
||||
if (!accessToken) {
|
||||
throw new Error("Matrix login did not return an access token");
|
||||
throw new Error(`Matrix login did not return an access token for account ${accountId ?? "default"}`);
|
||||
}
|
||||
|
||||
const auth: MatrixAuth = {
|
||||
|
|
@ -154,12 +202,15 @@ export async function resolveMatrixAuth(params?: {
|
|||
encryption: resolved.encryption,
|
||||
};
|
||||
|
||||
saveMatrixCredentials({
|
||||
homeserver: auth.homeserver,
|
||||
userId: auth.userId,
|
||||
accessToken: auth.accessToken,
|
||||
deviceId: login.device_id,
|
||||
});
|
||||
// Only save credentials for default account
|
||||
if (isDefaultAccount) {
|
||||
saveMatrixCredentials({
|
||||
homeserver: auth.homeserver,
|
||||
userId: auth.userId,
|
||||
accessToken: auth.accessToken,
|
||||
deviceId: login.device_id,
|
||||
});
|
||||
}
|
||||
|
||||
return auth;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi
|
|||
},
|
||||
};
|
||||
|
||||
const auth = await resolveMatrixAuth({ cfg });
|
||||
const auth = await resolveMatrixAuth({ cfg, accountId: opts.accountId });
|
||||
const resolvedInitialSyncLimit =
|
||||
typeof opts.initialSyncLimit === "number"
|
||||
? Math.max(0, Math.floor(opts.initialSyncLimit))
|
||||
|
|
|
|||
|
|
@ -38,10 +38,10 @@ export type MatrixActionConfig = {
|
|||
channelInfo?: boolean;
|
||||
};
|
||||
|
||||
export type MatrixConfig = {
|
||||
export type MatrixAccountConfig = {
|
||||
/** Optional display name for this account (used in CLI/UI lists). */
|
||||
name?: string;
|
||||
/** If false, do not start Matrix. Default: true. */
|
||||
/** If false, do not start this account. Default: true. */
|
||||
enabled?: boolean;
|
||||
/** Matrix homeserver URL (https://matrix.example.org). */
|
||||
homeserver?: string;
|
||||
|
|
@ -87,9 +87,22 @@ export type MatrixConfig = {
|
|||
actions?: MatrixActionConfig;
|
||||
};
|
||||
|
||||
export type MatrixConfig = {
|
||||
/** Optional per-account Matrix configuration (multi-account). */
|
||||
accounts?: Record<string, MatrixAccountConfig>;
|
||||
} & MatrixAccountConfig;
|
||||
|
||||
export type CoreConfig = {
|
||||
channels?: {
|
||||
matrix?: MatrixConfig;
|
||||
};
|
||||
bindings?: Array<{
|
||||
agentId?: string;
|
||||
match?: {
|
||||
channel?: string;
|
||||
accountId?: string;
|
||||
peer?: { kind?: string; id?: string };
|
||||
};
|
||||
}>;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue