Matrix-js: migrate account-scoped defaults into accounts.default

This commit is contained in:
Gustavo Madeira Santana
2026-02-25 20:54:20 -05:00
parent 60ac0899c7
commit 3911be9795
2 changed files with 113 additions and 10 deletions

View File

@@ -200,11 +200,17 @@ describe("matrix directory", () => {
const cfg = {
channels: {
"matrix-js": {
name: "pinguini",
homeserver: "https://legacy.example.org",
userId: "@legacy:example.org",
accessToken: "legacy-token",
deviceName: "Legacy Device",
encryption: true,
groupPolicy: "allowlist",
groups: {
"!legacy-room:example.org": { allow: true },
},
register: false,
},
},
} as unknown as CoreConfig;
@@ -213,12 +219,46 @@ describe("matrix directory", () => {
expect(updated.channels?.["matrix-js"]?.homeserver).toBeUndefined();
expect(updated.channels?.["matrix-js"]?.accessToken).toBeUndefined();
expect(updated.channels?.["matrix-js"]?.deviceName).toBeUndefined();
expect(updated.channels?.["matrix-js"]?.encryption).toBe(true);
expect(updated.channels?.["matrix-js"]?.encryption).toBeUndefined();
expect((updated.channels?.["matrix-js"] as Record<string, unknown>)?.register).toBeUndefined();
expect(updated.channels?.["matrix-js"]?.accounts?.default).toMatchObject({
name: "pinguini",
homeserver: "https://legacy.example.org",
userId: "@legacy:example.org",
accessToken: "legacy-token",
deviceName: "Legacy Device",
encryption: true,
groupPolicy: "allowlist",
groups: {
"!legacy-room:example.org": { allow: true },
},
});
});
it("merges top-level object defaults into accounts.default during migration", () => {
const cfg = {
channels: {
"matrix-js": {
dm: {
policy: "allowlist",
allowFrom: ["@legacy:example.org"],
},
accounts: {
default: {
dm: {
policy: "pairing",
},
},
},
},
},
} as unknown as CoreConfig;
const updated = migrateMatrixLegacyCredentialsToDefaultAccount(cfg);
expect(updated.channels?.["matrix-js"]?.dm).toBeUndefined();
expect(updated.channels?.["matrix-js"]?.accounts?.default?.dm).toMatchObject({
policy: "pairing",
allowFrom: ["@legacy:example.org"],
});
});

View File

@@ -2,15 +2,33 @@ import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk";
import type { CoreConfig, MatrixAccountConfig, MatrixConfig } from "./types.js";
type LegacyAccountField =
| "name"
| "homeserver"
| "userId"
| "accessToken"
| "password"
| "deviceId"
| "deviceName"
| "initialSyncLimit";
| "initialSyncLimit"
| "encryption"
| "allowlistOnly"
| "groupPolicy"
| "groupAllowFrom"
| "replyToMode"
| "threadReplies"
| "textChunkLimit"
| "chunkMode"
| "responsePrefix"
| "mediaMaxMb"
| "autoJoin"
| "autoJoinAllowlist"
| "dm"
| "groups"
| "rooms"
| "actions";
const LEGACY_ACCOUNT_FIELDS: ReadonlyArray<LegacyAccountField> = [
"name",
"homeserver",
"userId",
"accessToken",
@@ -18,8 +36,49 @@ const LEGACY_ACCOUNT_FIELDS: ReadonlyArray<LegacyAccountField> = [
"deviceId",
"deviceName",
"initialSyncLimit",
"encryption",
"allowlistOnly",
"groupPolicy",
"groupAllowFrom",
"replyToMode",
"threadReplies",
"textChunkLimit",
"chunkMode",
"responsePrefix",
"mediaMaxMb",
"autoJoin",
"autoJoinAllowlist",
"dm",
"groups",
"rooms",
"actions",
];
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function mergeLegacyFieldIntoDefault(
current: MatrixAccountConfig[LegacyAccountField] | undefined,
legacy: MatrixAccountConfig[LegacyAccountField],
): MatrixAccountConfig[LegacyAccountField] {
if (current === undefined) {
return legacy;
}
if (isRecord(current) && isRecord(legacy)) {
return {
...legacy,
...current,
} as MatrixAccountConfig[LegacyAccountField];
}
return current;
}
function clearLegacyOnlyFields(nextMatrix: MatrixConfig): void {
// Legacy matrix-bot-sdk onboarding toggle; not used by matrix-js config.
delete (nextMatrix as Record<string, unknown>).register;
}
export function migrateMatrixLegacyCredentialsToDefaultAccount(cfg: CoreConfig): CoreConfig {
const matrix = cfg.channels?.["matrix-js"];
if (!matrix) {
@@ -36,14 +95,17 @@ export function migrateMatrixLegacyCredentialsToDefaultAccount(cfg: CoreConfig):
if (legacyValue === undefined) {
continue;
}
if (defaultAccount[field] === undefined) {
(
defaultAccount as Record<
LegacyAccountField,
MatrixAccountConfig[LegacyAccountField] | undefined
>
)[field] = legacyValue;
}
(
defaultAccount as Record<
LegacyAccountField,
MatrixAccountConfig[LegacyAccountField] | undefined
>
)[field] = mergeLegacyFieldIntoDefault(defaultAccount[field], legacyValue);
changed = true;
}
const registerPresent = (matrix as Record<string, unknown>).register !== undefined;
if (registerPresent) {
changed = true;
}
@@ -55,6 +117,7 @@ export function migrateMatrixLegacyCredentialsToDefaultAccount(cfg: CoreConfig):
for (const field of LEGACY_ACCOUNT_FIELDS) {
delete nextMatrix[field];
}
clearLegacyOnlyFields(nextMatrix);
nextMatrix.accounts = {
...matrix.accounts,
[DEFAULT_ACCOUNT_ID]: defaultAccount,