mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-02 13:31:38 +00:00
* fix(extensions): make indexed access explicit across channel plugins Transport-payload-safe burn-down: malformed Telegram/Discord/QQ/LINE and sibling channel input keeps existing skip paths; no synthesized fields, no new throws in delivery loops. Zalo escape sentinels preserve literal matches instead of undefined replacements. * fix(extensions): make indexed access explicit across provider and memory plugins Stream and model iteration, tool-block guards, capture guards, and sparse accumulators; singleton model reads carry named invariants. * fix(extensions): make indexed access explicit across tooling plugins, flip the extensions lane Remaining plugins (oc-path, qa-lab, browser, logbook, and siblings) plus the tsconfig.extensions.json flag flip. Cleanup: logbook sampleFrames NaN index at max=1, QA retry clamp at non-positive attempts, dead Canvas probe and OpenShell no-op slice removed, twitch test setup leak excluded from the prod lane. * refactor(plugin-sdk): expose expectDefined via a focused SDK subpath Extensions imported @openclaw/normalization-core directly, crossing the external-plugin packaging boundary (it only worked because the runtime builder bundles undeclared workspace helpers). expect-runtime joins the canonical entrypoints JSON, generated exports, API baseline, docs, and subpath contract test; all 78 extension imports now use the SDK seam. Two scanner-shaped locals renamed for review-bundle hygiene. * chore(plugin-sdk): raise surface budgets for the expect-runtime subpath One new entrypoint with one callable export, added intentionally as the packaging-honest seam for extension invariant helpers.
98 lines
2.9 KiB
TypeScript
98 lines
2.9 KiB
TypeScript
// Matrix plugin module implements env vars behavior.
|
|
import { normalizeAccountId, normalizeOptionalAccountId } from "openclaw/plugin-sdk/account-id";
|
|
|
|
const MATRIX_SCOPED_ENV_SUFFIXES = [
|
|
"HOMESERVER",
|
|
"USER_ID",
|
|
"ACCESS_TOKEN",
|
|
"PASSWORD",
|
|
"DEVICE_ID",
|
|
"DEVICE_NAME",
|
|
] as const;
|
|
const MATRIX_GLOBAL_ENV_KEYS = MATRIX_SCOPED_ENV_SUFFIXES.map((suffix) => `MATRIX_${suffix}`);
|
|
|
|
const MATRIX_SCOPED_ENV_RE = new RegExp(`^MATRIX_(.+)_(${MATRIX_SCOPED_ENV_SUFFIXES.join("|")})$`);
|
|
|
|
export function resolveMatrixEnvAccountToken(accountId: string): string {
|
|
return Array.from(normalizeAccountId(accountId))
|
|
.map((char) =>
|
|
/[a-z0-9]/.test(char)
|
|
? char.toUpperCase()
|
|
: `_X${char.codePointAt(0)?.toString(16).toUpperCase() ?? "00"}_`,
|
|
)
|
|
.join("");
|
|
}
|
|
|
|
export function getMatrixScopedEnvVarNames(accountId: string): {
|
|
homeserver: string;
|
|
userId: string;
|
|
accessToken: string;
|
|
password: string;
|
|
deviceId: string;
|
|
deviceName: string;
|
|
} {
|
|
const token = resolveMatrixEnvAccountToken(accountId);
|
|
return {
|
|
homeserver: `MATRIX_${token}_HOMESERVER`,
|
|
userId: `MATRIX_${token}_USER_ID`,
|
|
accessToken: `MATRIX_${token}_ACCESS_TOKEN`,
|
|
password: `MATRIX_${token}_PASSWORD`,
|
|
deviceId: `MATRIX_${token}_DEVICE_ID`,
|
|
deviceName: `MATRIX_${token}_DEVICE_NAME`,
|
|
};
|
|
}
|
|
|
|
function decodeMatrixEnvAccountToken(token: string): string | undefined {
|
|
let decoded = "";
|
|
for (let index = 0; index < token.length;) {
|
|
const hexEscape = /^_X([0-9A-F]+)_/.exec(token.slice(index));
|
|
if (hexEscape) {
|
|
const hex = hexEscape[1];
|
|
const codePoint = hex ? Number.parseInt(hex, 16) : Number.NaN;
|
|
if (!Number.isFinite(codePoint)) {
|
|
return undefined;
|
|
}
|
|
const char = String.fromCodePoint(codePoint);
|
|
decoded += char;
|
|
index += hexEscape[0].length;
|
|
continue;
|
|
}
|
|
const char = token[index];
|
|
if (!char || !/[A-Z0-9]/.test(char)) {
|
|
return undefined;
|
|
}
|
|
decoded += char.toLowerCase();
|
|
index += 1;
|
|
}
|
|
const normalized = normalizeOptionalAccountId(decoded);
|
|
if (!normalized) {
|
|
return undefined;
|
|
}
|
|
return resolveMatrixEnvAccountToken(normalized) === token ? normalized : undefined;
|
|
}
|
|
|
|
export function listMatrixEnvAccountIds(env: NodeJS.ProcessEnv = process.env): string[] {
|
|
const ids = new Set<string>();
|
|
for (const key of MATRIX_GLOBAL_ENV_KEYS) {
|
|
if (typeof env[key] === "string" && env[key]?.trim()) {
|
|
ids.add(normalizeAccountId("default"));
|
|
break;
|
|
}
|
|
}
|
|
for (const key of Object.keys(env)) {
|
|
const match = MATRIX_SCOPED_ENV_RE.exec(key);
|
|
if (!match) {
|
|
continue;
|
|
}
|
|
const encodedAccountId = match[1];
|
|
if (!encodedAccountId) {
|
|
continue;
|
|
}
|
|
const accountId = decodeMatrixEnvAccountToken(encodedAccountId);
|
|
if (accountId) {
|
|
ids.add(accountId);
|
|
}
|
|
}
|
|
return Array.from(ids).toSorted((a, b) => a.localeCompare(b));
|
|
}
|