Matrix: fix verification client lifecycle and quiet CLI noise

This commit is contained in:
Gustavo Madeira Santana
2026-03-09 02:56:02 -04:00
parent a3573ac71f
commit df6b6762c0
12 changed files with 144 additions and 24 deletions

View File

@@ -12,6 +12,7 @@ const matrixSetupValidateInputMock = vi.fn();
const matrixRuntimeLoadConfigMock = vi.fn(); const matrixRuntimeLoadConfigMock = vi.fn();
const matrixRuntimeWriteConfigFileMock = vi.fn(); const matrixRuntimeWriteConfigFileMock = vi.fn();
const restoreMatrixRoomKeyBackupMock = vi.fn(); const restoreMatrixRoomKeyBackupMock = vi.fn();
const setMatrixSdkConsoleLoggingMock = vi.fn();
const setMatrixSdkLogModeMock = vi.fn(); const setMatrixSdkLogModeMock = vi.fn();
const updateMatrixOwnProfileMock = vi.fn(); const updateMatrixOwnProfileMock = vi.fn();
const verifyMatrixRecoveryKeyMock = vi.fn(); const verifyMatrixRecoveryKeyMock = vi.fn();
@@ -25,6 +26,7 @@ vi.mock("./matrix/actions/verification.js", () => ({
})); }));
vi.mock("./matrix/client/logging.js", () => ({ vi.mock("./matrix/client/logging.js", () => ({
setMatrixSdkConsoleLogging: (...args: unknown[]) => setMatrixSdkConsoleLoggingMock(...args),
setMatrixSdkLogMode: (...args: unknown[]) => setMatrixSdkLogModeMock(...args), setMatrixSdkLogMode: (...args: unknown[]) => setMatrixSdkLogModeMock(...args),
})); }));

View File

@@ -14,7 +14,7 @@ import {
restoreMatrixRoomKeyBackup, restoreMatrixRoomKeyBackup,
verifyMatrixRecoveryKey, verifyMatrixRecoveryKey,
} from "./matrix/actions/verification.js"; } from "./matrix/actions/verification.js";
import { setMatrixSdkLogMode } from "./matrix/client/logging.js"; import { setMatrixSdkConsoleLogging, setMatrixSdkLogMode } from "./matrix/client/logging.js";
import { resolveMatrixConfigPath, updateMatrixAccountConfig } from "./matrix/config-update.js"; import { resolveMatrixConfigPath, updateMatrixAccountConfig } from "./matrix/config-update.js";
import { applyMatrixProfileUpdate, type MatrixProfileUpdateResult } from "./profile-update.js"; import { applyMatrixProfileUpdate, type MatrixProfileUpdateResult } from "./profile-update.js";
import { getMatrixRuntime } from "./runtime.js"; import { getMatrixRuntime } from "./runtime.js";
@@ -69,6 +69,7 @@ function printAccountLabel(accountId?: string): void {
function configureCliLogMode(verbose: boolean): void { function configureCliLogMode(verbose: boolean): void {
setMatrixSdkLogMode(verbose ? "default" : "quiet"); setMatrixSdkLogMode(verbose ? "default" : "quiet");
setMatrixSdkConsoleLogging(verbose);
} }
function parseOptionalInt(value: string | undefined, fieldName: string): number | undefined { function parseOptionalInt(value: string | undefined, fieldName: string): number | undefined {

View File

@@ -32,6 +32,7 @@ let resolveActionClient: typeof import("./client.js").resolveActionClient;
function createMockMatrixClient(): MatrixClient { function createMockMatrixClient(): MatrixClient {
return { return {
prepareForOneOff: vi.fn(async () => undefined), prepareForOneOff: vi.fn(async () => undefined),
start: vi.fn(async () => undefined),
} as unknown as MatrixClient; } as unknown as MatrixClient;
} }
@@ -92,6 +93,30 @@ describe("resolveActionClient", () => {
expect(result.stopOnDone).toBe(true); expect(result.stopOnDone).toBe(true);
}); });
it("skips one-off room preparation when readiness is disabled", async () => {
const result = await resolveActionClient({
accountId: "default",
readiness: "none",
});
const oneOffClient = await createMatrixClientMock.mock.results[0]?.value;
expect(oneOffClient.prepareForOneOff).not.toHaveBeenCalled();
expect(oneOffClient.start).not.toHaveBeenCalled();
expect(result.stopOnDone).toBe(true);
});
it("starts one-off clients when started readiness is required", async () => {
const result = await resolveActionClient({
accountId: "default",
readiness: "started",
});
const oneOffClient = await createMatrixClientMock.mock.results[0]?.value;
expect(oneOffClient.start).toHaveBeenCalledTimes(1);
expect(oneOffClient.prepareForOneOff).not.toHaveBeenCalled();
expect(result.stopOnDone).toBe(true);
});
it("reuses active monitor client when available", async () => { it("reuses active monitor client when available", async () => {
const activeClient = createMockMatrixClient(); const activeClient = createMockMatrixClient();
getActiveMatrixClientMock.mockReturnValue(activeClient); getActiveMatrixClientMock.mockReturnValue(activeClient);
@@ -103,6 +128,20 @@ describe("resolveActionClient", () => {
expect(createMatrixClientMock).not.toHaveBeenCalled(); expect(createMatrixClientMock).not.toHaveBeenCalled();
}); });
it("starts active clients when started readiness is required", async () => {
const activeClient = createMockMatrixClient();
getActiveMatrixClientMock.mockReturnValue(activeClient);
const result = await resolveActionClient({
accountId: "default",
readiness: "started",
});
expect(result).toEqual({ client: activeClient, stopOnDone: false });
expect(activeClient.start).toHaveBeenCalledTimes(1);
expect(activeClient.prepareForOneOff).not.toHaveBeenCalled();
});
it("uses the implicit resolved account id for active client lookup and storage", async () => { it("uses the implicit resolved account id for active client lookup and storage", async () => {
loadConfigMock.mockReturnValue({ loadConfigMock.mockReturnValue({
channels: { channels: {

View File

@@ -15,11 +15,28 @@ export function ensureNodeRuntime() {
} }
} }
async function ensureActionClientReadiness(
client: MatrixActionClient["client"],
readiness: MatrixActionClientOpts["readiness"],
opts: { createdForOneOff: boolean },
): Promise<void> {
if (readiness === "started") {
await client.start();
return;
}
if (readiness === "prepared" || (!readiness && opts.createdForOneOff)) {
await client.prepareForOneOff();
}
}
export async function resolveActionClient( export async function resolveActionClient(
opts: MatrixActionClientOpts = {}, opts: MatrixActionClientOpts = {},
): Promise<MatrixActionClient> { ): Promise<MatrixActionClient> {
ensureNodeRuntime(); ensureNodeRuntime();
if (opts.client) { if (opts.client) {
await ensureActionClientReadiness(opts.client, opts.readiness, {
createdForOneOff: false,
});
return { client: opts.client, stopOnDone: false }; return { client: opts.client, stopOnDone: false };
} }
const cfg = getMatrixRuntime().config.loadConfig() as CoreConfig; const cfg = getMatrixRuntime().config.loadConfig() as CoreConfig;
@@ -29,6 +46,9 @@ export async function resolveActionClient(
}); });
const active = getActiveMatrixClient(authContext.accountId); const active = getActiveMatrixClient(authContext.accountId);
if (active) { if (active) {
await ensureActionClientReadiness(active, opts.readiness, {
createdForOneOff: false,
});
return { client: active, stopOnDone: false }; return { client: active, stopOnDone: false };
} }
const auth = await resolveMatrixAuth({ const auth = await resolveMatrixAuth({
@@ -46,7 +66,9 @@ export async function resolveActionClient(
accountId: auth.accountId, accountId: auth.accountId,
autoBootstrapCrypto: false, autoBootstrapCrypto: false,
}); });
await client.prepareForOneOff(); await ensureActionClientReadiness(client, opts.readiness, {
createdForOneOff: true,
});
return { client, stopOnDone: true }; return { client, stopOnDone: true };
} }

View File

@@ -48,6 +48,7 @@ export type MatrixActionClientOpts = {
client?: MatrixClient; client?: MatrixClient;
timeoutMs?: number; timeoutMs?: number;
accountId?: string | null; accountId?: string | null;
readiness?: "none" | "prepared" | "started";
}; };
export type MatrixMessageSummary = { export type MatrixMessageSummary = {

View File

@@ -20,7 +20,7 @@ function resolveVerificationId(input: string): string {
export async function listMatrixVerifications(opts: MatrixActionClientOpts = {}) { export async function listMatrixVerifications(opts: MatrixActionClientOpts = {}) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => { async (client) => {
const crypto = requireCrypto(client); const crypto = requireCrypto(client);
return await crypto.listVerifications(); return await crypto.listVerifications();
@@ -38,7 +38,7 @@ export async function requestMatrixVerification(
} = {}, } = {},
) { ) {
return await withResolvedActionClient( return await withResolvedActionClient(
params, { ...params, readiness: "started" },
async (client) => { async (client) => {
const crypto = requireCrypto(client); const crypto = requireCrypto(client);
const ownUser = params.ownUser ?? (!params.userId && !params.deviceId && !params.roomId); const ownUser = params.ownUser ?? (!params.userId && !params.deviceId && !params.roomId);
@@ -58,7 +58,7 @@ export async function acceptMatrixVerification(
opts: MatrixActionClientOpts = {}, opts: MatrixActionClientOpts = {},
) { ) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => { async (client) => {
const crypto = requireCrypto(client); const crypto = requireCrypto(client);
return await crypto.acceptVerification(resolveVerificationId(requestId)); return await crypto.acceptVerification(resolveVerificationId(requestId));
@@ -72,7 +72,7 @@ export async function cancelMatrixVerification(
opts: MatrixActionClientOpts & { reason?: string; code?: string } = {}, opts: MatrixActionClientOpts & { reason?: string; code?: string } = {},
) { ) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => { async (client) => {
const crypto = requireCrypto(client); const crypto = requireCrypto(client);
return await crypto.cancelVerification(resolveVerificationId(requestId), { return await crypto.cancelVerification(resolveVerificationId(requestId), {
@@ -89,7 +89,7 @@ export async function startMatrixVerification(
opts: MatrixActionClientOpts & { method?: "sas" } = {}, opts: MatrixActionClientOpts & { method?: "sas" } = {},
) { ) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => { async (client) => {
const crypto = requireCrypto(client); const crypto = requireCrypto(client);
return await crypto.startVerification(resolveVerificationId(requestId), opts.method ?? "sas"); return await crypto.startVerification(resolveVerificationId(requestId), opts.method ?? "sas");
@@ -103,7 +103,7 @@ export async function generateMatrixVerificationQr(
opts: MatrixActionClientOpts = {}, opts: MatrixActionClientOpts = {},
) { ) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => { async (client) => {
const crypto = requireCrypto(client); const crypto = requireCrypto(client);
return await crypto.generateVerificationQr(resolveVerificationId(requestId)); return await crypto.generateVerificationQr(resolveVerificationId(requestId));
@@ -118,7 +118,7 @@ export async function scanMatrixVerificationQr(
opts: MatrixActionClientOpts = {}, opts: MatrixActionClientOpts = {},
) { ) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => { async (client) => {
const crypto = requireCrypto(client); const crypto = requireCrypto(client);
const payload = qrDataBase64.trim(); const payload = qrDataBase64.trim();
@@ -136,7 +136,7 @@ export async function getMatrixVerificationSas(
opts: MatrixActionClientOpts = {}, opts: MatrixActionClientOpts = {},
) { ) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => { async (client) => {
const crypto = requireCrypto(client); const crypto = requireCrypto(client);
return await crypto.getVerificationSas(resolveVerificationId(requestId)); return await crypto.getVerificationSas(resolveVerificationId(requestId));
@@ -150,7 +150,7 @@ export async function confirmMatrixVerificationSas(
opts: MatrixActionClientOpts = {}, opts: MatrixActionClientOpts = {},
) { ) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => { async (client) => {
const crypto = requireCrypto(client); const crypto = requireCrypto(client);
return await crypto.confirmVerificationSas(resolveVerificationId(requestId)); return await crypto.confirmVerificationSas(resolveVerificationId(requestId));
@@ -164,7 +164,7 @@ export async function mismatchMatrixVerificationSas(
opts: MatrixActionClientOpts = {}, opts: MatrixActionClientOpts = {},
) { ) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => { async (client) => {
const crypto = requireCrypto(client); const crypto = requireCrypto(client);
return await crypto.mismatchVerificationSas(resolveVerificationId(requestId)); return await crypto.mismatchVerificationSas(resolveVerificationId(requestId));
@@ -178,7 +178,7 @@ export async function confirmMatrixVerificationReciprocateQr(
opts: MatrixActionClientOpts = {}, opts: MatrixActionClientOpts = {},
) { ) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => { async (client) => {
const crypto = requireCrypto(client); const crypto = requireCrypto(client);
return await crypto.confirmVerificationReciprocateQr(resolveVerificationId(requestId)); return await crypto.confirmVerificationReciprocateQr(resolveVerificationId(requestId));
@@ -191,7 +191,7 @@ export async function getMatrixEncryptionStatus(
opts: MatrixActionClientOpts & { includeRecoveryKey?: boolean } = {}, opts: MatrixActionClientOpts & { includeRecoveryKey?: boolean } = {},
) { ) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => { async (client) => {
const crypto = requireCrypto(client); const crypto = requireCrypto(client);
const recoveryKey = await crypto.getRecoveryKey(); const recoveryKey = await crypto.getRecoveryKey();
@@ -211,7 +211,7 @@ export async function getMatrixVerificationStatus(
opts: MatrixActionClientOpts & { includeRecoveryKey?: boolean } = {}, opts: MatrixActionClientOpts & { includeRecoveryKey?: boolean } = {},
) { ) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => { async (client) => {
const status = await client.getOwnDeviceVerificationStatus(); const status = await client.getOwnDeviceVerificationStatus();
const payload = { const payload = {
@@ -233,7 +233,7 @@ export async function getMatrixVerificationStatus(
export async function getMatrixRoomKeyBackupStatus(opts: MatrixActionClientOpts = {}) { export async function getMatrixRoomKeyBackupStatus(opts: MatrixActionClientOpts = {}) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => await client.getRoomKeyBackupStatus(), async (client) => await client.getRoomKeyBackupStatus(),
"persist", "persist",
); );
@@ -244,7 +244,7 @@ export async function verifyMatrixRecoveryKey(
opts: MatrixActionClientOpts = {}, opts: MatrixActionClientOpts = {},
) { ) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => await client.verifyWithRecoveryKey(recoveryKey), async (client) => await client.verifyWithRecoveryKey(recoveryKey),
"persist", "persist",
); );
@@ -256,7 +256,7 @@ export async function restoreMatrixRoomKeyBackup(
} = {}, } = {},
) { ) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => async (client) =>
await client.restoreRoomKeyBackup({ await client.restoreRoomKeyBackup({
recoveryKey: opts.recoveryKey?.trim() || undefined, recoveryKey: opts.recoveryKey?.trim() || undefined,
@@ -272,7 +272,7 @@ export async function bootstrapMatrixVerification(
} = {}, } = {},
) { ) {
return await withResolvedActionClient( return await withResolvedActionClient(
opts, { ...opts, readiness: "started" },
async (client) => async (client) =>
await client.bootstrapOwnDeviceVerification({ await client.bootstrapOwnDeviceVerification({
recoveryKey: opts.recoveryKey?.trim() || undefined, recoveryKey: opts.recoveryKey?.trim() || undefined,

View File

@@ -1,8 +1,12 @@
import { ConsoleLogger, LogService } from "../sdk/logger.js"; import { logger as matrixJsSdkRootLogger } from "matrix-js-sdk/lib/logger.js";
import { ConsoleLogger, LogService, setMatrixConsoleLogging } from "../sdk/logger.js";
let matrixSdkLoggingConfigured = false; let matrixSdkLoggingConfigured = false;
let matrixSdkLogMode: "default" | "quiet" = "default"; let matrixSdkLogMode: "default" | "quiet" = "default";
const matrixSdkBaseLogger = new ConsoleLogger(); const matrixSdkBaseLogger = new ConsoleLogger();
const matrixSdkSilentMethodFactory = () => () => {};
let matrixSdkRootMethodFactory: unknown;
let matrixSdkRootLoggerInitialized = false;
type MatrixJsSdkLogger = { type MatrixJsSdkLogger = {
trace: (...messageOrObject: unknown[]) => void; trace: (...messageOrObject: unknown[]) => void;
@@ -40,11 +44,30 @@ export function setMatrixSdkLogMode(mode: "default" | "quiet"): void {
applyMatrixSdkLogger(); applyMatrixSdkLogger();
} }
export function setMatrixSdkConsoleLogging(enabled: boolean): void {
setMatrixConsoleLogging(enabled);
}
export function createMatrixJsSdkClientLogger(prefix = "matrix"): MatrixJsSdkLogger { export function createMatrixJsSdkClientLogger(prefix = "matrix"): MatrixJsSdkLogger {
return createMatrixJsSdkLoggerInstance(prefix); return createMatrixJsSdkLoggerInstance(prefix);
} }
function applyMatrixJsSdkRootLoggerMode(): void {
const rootLogger = matrixJsSdkRootLogger as {
methodFactory?: unknown;
rebuild?: () => void;
};
if (!matrixSdkRootLoggerInitialized) {
matrixSdkRootMethodFactory = rootLogger.methodFactory;
matrixSdkRootLoggerInitialized = true;
}
rootLogger.methodFactory =
matrixSdkLogMode === "quiet" ? matrixSdkSilentMethodFactory : matrixSdkRootMethodFactory;
rootLogger.rebuild?.();
}
function applyMatrixSdkLogger(): void { function applyMatrixSdkLogger(): void {
applyMatrixJsSdkRootLoggerMode();
if (matrixSdkLogMode === "quiet") { if (matrixSdkLogMode === "quiet") {
LogService.setLogger({ LogService.setLogger({
trace: () => {}, trace: () => {},

View File

@@ -1068,13 +1068,13 @@ describe("MatrixClient crypto bootstrapping", () => {
encryption: true, encryption: true,
recoveryKeyPath: path.join(recoveryDir, "recovery-key.json"), recoveryKeyPath: path.join(recoveryDir, "recovery-key.json"),
}); });
await client.start();
const result = await client.verifyWithRecoveryKey(encoded as string); const result = await client.verifyWithRecoveryKey(encoded as string);
expect(result.success).toBe(true); expect(result.success).toBe(true);
expect(result.verified).toBe(true); expect(result.verified).toBe(true);
expect(result.recoveryKeyStored).toBe(true); expect(result.recoveryKeyStored).toBe(true);
expect(result.deviceId).toBe("DEVICE123"); expect(result.deviceId).toBe("DEVICE123");
expect(matrixJsClient.startClient).toHaveBeenCalledTimes(1);
expect(bootstrapSecretStorage).toHaveBeenCalled(); expect(bootstrapSecretStorage).toHaveBeenCalled();
expect(bootstrapCrossSigning).toHaveBeenCalled(); expect(bootstrapCrossSigning).toHaveBeenCalled();
}); });
@@ -1265,6 +1265,7 @@ describe("MatrixClient crypto bootstrapping", () => {
expect(result.imported).toBe(4); expect(result.imported).toBe(4);
expect(result.total).toBe(10); expect(result.total).toBe(10);
expect(result.loadedFromSecretStorage).toBe(true); expect(result.loadedFromSecretStorage).toBe(true);
expect(matrixJsClient.startClient).toHaveBeenCalledTimes(1);
expect(loadSessionBackupPrivateKeyFromSecretStorage).toHaveBeenCalledTimes(1); expect(loadSessionBackupPrivateKeyFromSecretStorage).toHaveBeenCalledTimes(1);
expect(restoreKeyBackup).toHaveBeenCalledTimes(1); expect(restoreKeyBackup).toHaveBeenCalledTimes(1);
}); });
@@ -1330,6 +1331,7 @@ describe("MatrixClient crypto bootstrapping", () => {
expect(result.error).toContain( expect(result.error).toContain(
"Cross-signing bootstrap finished but server keys are still not published", "Cross-signing bootstrap finished but server keys are still not published",
); );
expect(matrixJsClient.startClient).toHaveBeenCalledTimes(1);
}); });
it("reports bootstrap success when own device is verified and keys are published", async () => { it("reports bootstrap success when own device is verified and keys are published", async () => {

View File

@@ -247,6 +247,10 @@ export class MatrixClient {
private idbPersistTimer: ReturnType<typeof setInterval> | null = null; private idbPersistTimer: ReturnType<typeof setInterval> | null = null;
async start(): Promise<void> { async start(): Promise<void> {
await this.startSyncSession({ bootstrapCrypto: true });
}
private async startSyncSession(opts: { bootstrapCrypto: boolean }): Promise<void> {
if (this.started) { if (this.started) {
return; return;
} }
@@ -257,7 +261,7 @@ export class MatrixClient {
await this.client.startClient({ await this.client.startClient({
initialSyncLimit: this.initialSyncLimit, initialSyncLimit: this.initialSyncLimit,
}); });
if (this.autoBootstrapCrypto) { if (opts.bootstrapCrypto && this.autoBootstrapCrypto) {
await this.bootstrapCryptoIfNeeded(); await this.bootstrapCryptoIfNeeded();
} }
this.started = true; this.started = true;
@@ -281,6 +285,13 @@ export class MatrixClient {
} }
} }
private async ensureStartedForCryptoControlPlane(): Promise<void> {
if (this.started) {
return;
}
await this.startSyncSession({ bootstrapCrypto: false });
}
stop(): void { stop(): void {
if (this.idbPersistTimer) { if (this.idbPersistTimer) {
clearInterval(this.idbPersistTimer); clearInterval(this.idbPersistTimer);
@@ -740,6 +751,7 @@ export class MatrixClient {
return await fail("Matrix encryption is disabled for this client"); return await fail("Matrix encryption is disabled for this client");
} }
await this.ensureStartedForCryptoControlPlane();
const crypto = this.client.getCrypto() as MatrixCryptoBootstrapApi | undefined; const crypto = this.client.getCrypto() as MatrixCryptoBootstrapApi | undefined;
if (!crypto) { if (!crypto) {
return await fail("Matrix crypto is not available (start client with encryption enabled)"); return await fail("Matrix crypto is not available (start client with encryption enabled)");
@@ -808,7 +820,7 @@ export class MatrixClient {
return await fail("Matrix encryption is disabled for this client"); return await fail("Matrix encryption is disabled for this client");
} }
await this.initializeCryptoIfNeeded(); await this.ensureStartedForCryptoControlPlane();
const crypto = this.client.getCrypto() as MatrixCryptoBootstrapApi | undefined; const crypto = this.client.getCrypto() as MatrixCryptoBootstrapApi | undefined;
if (!crypto) { if (!crypto) {
return await fail("Matrix crypto is not available (start client with encryption enabled)"); return await fail("Matrix crypto is not available (start client with encryption enabled)");
@@ -925,7 +937,7 @@ export class MatrixClient {
let bootstrapError: string | undefined; let bootstrapError: string | undefined;
let bootstrapSummary: MatrixCryptoBootstrapResult | null = null; let bootstrapSummary: MatrixCryptoBootstrapResult | null = null;
try { try {
await this.initializeCryptoIfNeeded(); await this.ensureStartedForCryptoControlPlane();
const crypto = this.client.getCrypto() as MatrixCryptoBootstrapApi | undefined; const crypto = this.client.getCrypto() as MatrixCryptoBootstrapApi | undefined;
if (!crypto) { if (!crypto) {
throw new Error("Matrix crypto is not available (start client with encryption enabled)"); throw new Error("Matrix crypto is not available (start client with encryption enabled)");

View File

@@ -14,7 +14,16 @@ export function noop(): void {
// no-op // no-op
} }
let forceConsoleLogging = false;
export function setMatrixConsoleLogging(enabled: boolean): void {
forceConsoleLogging = enabled;
}
function resolveRuntimeLogger(module: string): RuntimeLogger | null { function resolveRuntimeLogger(module: string): RuntimeLogger | null {
if (forceConsoleLogging) {
return null;
}
try { try {
return getMatrixRuntime().logging.getChildLogger({ module: `matrix:${module}` }); return getMatrixRuntime().logging.getChildLogger({ module: `matrix:${module}` });
} catch { } catch {

View File

@@ -43,6 +43,12 @@ describe("warning filter", () => {
message: "SQLite is an experimental feature and might change at any time", message: "SQLite is an experimental feature and might change at any time",
}), }),
).toBe(true); ).toBe(true);
expect(
shouldIgnoreWarning({
name: "Warning",
message: "`--localstorage-file` was provided without a valid path",
}),
).toBe(true);
}); });
it("keeps unknown warnings visible", () => { it("keeps unknown warnings visible", () => {

View File

@@ -23,6 +23,9 @@ export function shouldIgnoreWarning(warning: ProcessWarning): boolean {
) { ) {
return true; return true;
} }
if (warning.message?.includes("`--localstorage-file` was provided without a valid path")) {
return true;
}
return false; return false;
} }