Skip to content

Commit 5e7043f

Browse files
committed
Merge branch 'develop' into valere/rtc/simple_encryption_manager
2 parents 07af3d9 + 4dbca98 commit 5e7043f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+899
-730
lines changed

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,32 @@
1+
Changes in [37.5.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v37.5.0) (2025-05-06)
2+
==================================================================================================
3+
## ✨ Features
4+
5+
* Stabilise MSC3765 ([#4767](https://github.com/matrix-org/matrix-js-sdk/pull/4767)). Contributed by @Johennes.
6+
* Inherit `methodFactory` extensions from the parent to the child loggers. ([#4809](https://github.com/matrix-org/matrix-js-sdk/pull/4809)). Contributed by @toger5.
7+
8+
## 🐛 Bug Fixes
9+
10+
* [Backport staging] Fix token refresh behaviour for non-expired tokens ([#4827](https://github.com/matrix-org/matrix-js-sdk/pull/4827)). Contributed by @RiotRobot.
11+
* Refactor how token refreshing works to be more resilient ([#4819](https://github.com/matrix-org/matrix-js-sdk/pull/4819)). Contributed by @t3chguy.
12+
13+
14+
Changes in [37.4.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v37.4.0) (2025-04-22)
15+
==================================================================================================
16+
## ✨ Features
17+
18+
* MatrixRTC: Add combined `toDeviceAndRoomKeyTransport` ([#4792](https://github.com/matrix-org/matrix-js-sdk/pull/4792)). Contributed by @toger5.
19+
* Make logging consistent for matrixRTC ([#4788](https://github.com/matrix-org/matrix-js-sdk/pull/4788)). Contributed by @toger5.
20+
* MatrixRTC: ToDevice distribution for media stream keys ([#4785](https://github.com/matrix-org/matrix-js-sdk/pull/4785)). Contributed by @BillCarsonFr.
21+
22+
## 🐛 Bug Fixes
23+
24+
* Fix token refresh racing with other requests and not using new token ([#4798](https://github.com/matrix-org/matrix-js-sdk/pull/4798)). Contributed by @t3chguy.
25+
* Fix fallback to MemoryCryptoStore when LocalStorage unavailable ([#4797](https://github.com/matrix-org/matrix-js-sdk/pull/4797)). Contributed by @t3chguy.
26+
* Remove duplicate `deleteSecretStorage` in `RustCrypto.resetEncryption` ([#4789](https://github.com/matrix-org/matrix-js-sdk/pull/4789)). Contributed by @florianduros.
27+
* Fix `RustCrypto.resetEncryption` failure ([#4772](https://github.com/matrix-org/matrix-js-sdk/pull/4772)). Contributed by @florianduros.
28+
29+
130
Changes in [37.3.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v37.3.0) (2025-04-08)
231
==================================================================================================
332
## ✨ Features

knip.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export default {
99
"src/crypto-api/index.ts",
1010
"src/testing.ts",
1111
"src/matrix.ts",
12+
"src/utils.ts", // not really an entrypoint but we have deprecated `defer` there
1213
"scripts/**",
1314
"spec/**",
1415
// XXX: these look entirely unused

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"name": "matrix-js-sdk",
3-
"version": "37.3.0",
3+
"version": "37.5.0",
44
"description": "Matrix Client-Server SDK for Javascript",
55
"engines": {
6-
"node": ">=20.0.0"
6+
"node": ">=22.0.0"
77
},
88
"scripts": {
99
"prepack": "yarn build",
@@ -56,7 +56,7 @@
5656
"bs58": "^6.0.0",
5757
"content-type": "^1.0.4",
5858
"jwt-decode": "^4.0.0",
59-
"loglevel": "^1.7.1",
59+
"loglevel": "^1.9.2",
6060
"matrix-events-sdk": "0.0.1",
6161
"matrix-widget-api": "^1.10.0",
6262
"oidc-client-ts": "^3.0.1",
@@ -121,7 +121,7 @@
121121
"rimraf": "^6.0.0",
122122
"ts-node": "^10.9.2",
123123
"typedoc": "^0.28.1",
124-
"typedoc-plugin-coverage": "^3.0.0",
124+
"typedoc-plugin-coverage": "^4.0.0",
125125
"typedoc-plugin-mdn-links": "^5.0.0",
126126
"typedoc-plugin-missing-exports": "^4.0.0",
127127
"typescript": "^5.4.2"

spec/integ/crypto/crypto.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ import {
5959
} from "../../../src/matrix";
6060
import { E2EKeyReceiver } from "../../test-utils/E2EKeyReceiver";
6161
import { type ISyncResponder, SyncResponder } from "../../test-utils/SyncResponder";
62-
import { defer, escapeRegExp } from "../../../src/utils";
62+
import { escapeRegExp } from "../../../src/utils";
6363
import { downloadDeviceToJsDevice } from "../../../src/rust-crypto/device-converter";
6464
import { flushPromises } from "../../test-utils/flushPromises";
6565
import {
@@ -1283,13 +1283,13 @@ describe("crypto", () => {
12831283
const inboundGroupSessionPromise = expectSendRoomKey("@bob:xyz", testOlmAccount);
12841284

12851285
// ... and finally, send the room key. We block the response until `sendRoomMessageDefer` completes.
1286-
const sendRoomMessageDefer = defer<FetchMock.MockResponse>();
1286+
const sendRoomMessageResolvers = Promise.withResolvers<FetchMock.MockResponse>();
12871287
const reqProm = new Promise<IContent>((resolve) => {
12881288
fetchMock.putOnce(
12891289
new RegExp("/send/m.room.encrypted/"),
12901290
async (url: string, opts: RequestInit): Promise<FetchMock.MockResponse> => {
12911291
resolve(JSON.parse(opts.body as string));
1292-
return await sendRoomMessageDefer.promise;
1292+
return await sendRoomMessageResolvers.promise;
12931293
},
12941294
{
12951295
// append to the list of intercepts on this path (since we have some tests that call
@@ -1318,7 +1318,7 @@ describe("crypto", () => {
13181318

13191319
// release the send request
13201320
const resp = { event_id: "$event_id" };
1321-
sendRoomMessageDefer.resolve(resp);
1321+
sendRoomMessageResolvers.resolve(resp);
13221322
expect(await sendProm).toEqual(resp);
13231323

13241324
// still pending at this point

spec/integ/crypto/megolm-backup.spec.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import { advanceTimersUntil, awaitDecryption, syncPromise } from "../../test-uti
3636
import * as testData from "../../test-utils/test-data";
3737
import { type KeyBackupInfo, type KeyBackupSession } from "../../../src/crypto-api/keybackup";
3838
import { flushPromises } from "../../test-utils/flushPromises";
39-
import { defer, type IDeferred } from "../../../src/utils";
4039
import { decodeRecoveryKey, DecryptionFailureCode, CryptoEvent, type CryptoApi } from "../../../src/crypto-api";
4140
import { type KeyBackup } from "../../../src/rust-crypto/backup.ts";
4241

@@ -861,7 +860,7 @@ describe("megolm-keys backup", () => {
861860
expect(await aliceCrypto.getKeyBackupInfo()).toStrictEqual(testData.SIGNED_BACKUP_DATA);
862861

863862
// Delete the backup and we are expecting the key backup to be disabled
864-
const keyBackupStatus = defer<boolean>();
863+
const keyBackupStatus = Promise.withResolvers<boolean>();
865864
aliceClient.once(CryptoEvent.KeyBackupStatus, (enabled) => keyBackupStatus.resolve(enabled));
866865
await aliceCrypto.deleteKeyBackupVersion(testData.SIGNED_BACKUP_DATA.version!);
867866
expect(await keyBackupStatus.promise).toBe(false);
@@ -1158,7 +1157,7 @@ describe("megolm-keys backup", () => {
11581157
// A check backup should happen at some point
11591158
await aliceCrypto.checkKeyBackupAndEnable();
11601159

1161-
const awaitHasQueriedNewBackup: IDeferred<void> = defer<void>();
1160+
const awaitHasQueriedNewBackup: PromiseWithResolvers<void> = Promise.withResolvers<void>();
11621161

11631162
fetchMock.get(
11641163
"express:/_matrix/client/v3/room_keys/keys/:room_id/:session_id",

spec/integ/crypto/verification.spec.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import {
4444
type Verifier,
4545
VerifierEvent,
4646
} from "../../../src/crypto-api/verification";
47-
import { defer, escapeRegExp } from "../../../src/utils";
47+
import { escapeRegExp } from "../../../src/utils";
4848
import { awaitDecryption, emitPromise, getSyncResponse, syncPromise } from "../../test-utils/test-utils";
4949
import { SyncResponder } from "../../test-utils/SyncResponder";
5050
import {
@@ -1540,10 +1540,10 @@ function expectSendToDeviceMessage(msgtype: string): Promise<{ messages: any }>
15401540
* @returns a map of secret name to promise that will resolve (with the id of the secret request) when the secret is requested.
15411541
*/
15421542
function mockSecretRequestAndGetPromises(): Map<string, Promise<string>> {
1543-
const mskRequestDefer = defer<string>();
1544-
const sskRequestDefer = defer<string>();
1545-
const uskRequestDefer = defer<string>();
1546-
const backupKeyRequestDefer = defer<string>();
1543+
const mskRequestResolvers = Promise.withResolvers<string>();
1544+
const sskRequestResolvers = Promise.withResolvers<string>();
1545+
const uskRequestResolvers = Promise.withResolvers<string>();
1546+
const backupKeyRequestResolvers = Promise.withResolvers<string>();
15471547

15481548
fetchMock.put(
15491549
new RegExp(`/_matrix/client/(r0|v3)/sendToDevice/m.secret.request`),
@@ -1555,13 +1555,13 @@ function mockSecretRequestAndGetPromises(): Map<string, Promise<string>> {
15551555
const name = content.name;
15561556
const requestId = content.request_id;
15571557
if (name == "m.cross_signing.user_signing") {
1558-
uskRequestDefer.resolve(requestId);
1558+
uskRequestResolvers.resolve(requestId);
15591559
} else if (name == "m.cross_signing.master") {
1560-
mskRequestDefer.resolve(requestId);
1560+
mskRequestResolvers.resolve(requestId);
15611561
} else if (name == "m.cross_signing.self_signing") {
1562-
sskRequestDefer.resolve(requestId);
1562+
sskRequestResolvers.resolve(requestId);
15631563
} else if (name == "m.megolm_backup.v1") {
1564-
backupKeyRequestDefer.resolve(requestId);
1564+
backupKeyRequestResolvers.resolve(requestId);
15651565
}
15661566
}
15671567
return {};
@@ -1570,10 +1570,10 @@ function mockSecretRequestAndGetPromises(): Map<string, Promise<string>> {
15701570
);
15711571

15721572
const promiseMap = new Map<string, Promise<string>>();
1573-
promiseMap.set("m.cross_signing.master", mskRequestDefer.promise);
1574-
promiseMap.set("m.cross_signing.self_signing", sskRequestDefer.promise);
1575-
promiseMap.set("m.cross_signing.user_signing", uskRequestDefer.promise);
1576-
promiseMap.set("m.megolm_backup.v1", backupKeyRequestDefer.promise);
1573+
promiseMap.set("m.cross_signing.master", mskRequestResolvers.promise);
1574+
promiseMap.set("m.cross_signing.self_signing", sskRequestResolvers.promise);
1575+
promiseMap.set("m.cross_signing.user_signing", uskRequestResolvers.promise);
1576+
promiseMap.set("m.megolm_backup.v1", backupKeyRequestResolvers.promise);
15771577
return promiseMap;
15781578
}
15791579

@@ -1604,7 +1604,7 @@ function sha256(commitmentStr: string): string {
16041604
return encodeUnpaddedBase64(createHash("sha256").update(commitmentStr, "utf8").digest());
16051605
}
16061606

1607-
function encodeUnpaddedBase64(uint8Array: ArrayBuffer | Uint8Array): string {
1607+
function encodeUnpaddedBase64(uint8Array: ArrayLike<number>): string {
16081608
return Buffer.from(uint8Array).toString("base64").replace(/=+$/g, "");
16091609
}
16101610

@@ -1638,7 +1638,7 @@ function buildReadyMessage(
16381638
}
16391639

16401640
/** build an m.key.verification.start to-device message suitable for the m.reciprocate.v1 flow, originating from the dummy device */
1641-
function buildReciprocateStartMessage(transactionId: string, sharedSecret: ArrayBuffer) {
1641+
function buildReciprocateStartMessage(transactionId: string, sharedSecret: ArrayLike<number>) {
16421642
return {
16431643
type: "m.key.verification.start",
16441644
content: {

spec/integ/matrix-client-methods.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1796,6 +1796,27 @@ describe("MatrixClient", function () {
17961796
expect(client.getUserIdLocalpart()).toBe("alice");
17971797
});
17981798
});
1799+
1800+
describe("setRoomMutePushRule", () => {
1801+
it("should set room push rule to muted", async () => {
1802+
const roomId = "!roomId:server";
1803+
const client = new MatrixClient({
1804+
baseUrl: "http://localhost",
1805+
fetchFn: httpBackend.fetchFn as typeof globalThis.fetch,
1806+
});
1807+
client.pushRules = {
1808+
global: {
1809+
room: [{ rule_id: roomId, actions: [], default: false, enabled: false }],
1810+
},
1811+
};
1812+
1813+
const path = `/pushrules/global/room/${encodeURIComponent(roomId)}`;
1814+
httpBackend.when("DELETE", path).respond(200, {});
1815+
httpBackend.when("PUT", path).respond(200, {});
1816+
client.setRoomMutePushRule("global", roomId, true);
1817+
await httpBackend.flush("");
1818+
});
1819+
});
17991820
});
18001821

18011822
function withThreadId(event: MatrixEvent, newThreadId: string): MatrixEvent {

spec/integ/rendezvous/MSC4108SignInWithQR.spec.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import {
2626
PayloadType,
2727
RendezvousError,
2828
} from "../../../src/rendezvous";
29-
import { defer } from "../../../src/utils";
3029
import {
3130
ClientPrefix,
3231
DEVICE_CODE_SCOPE,
@@ -112,8 +111,8 @@ describe("MSC4108SignInWithQR", () => {
112111
let opponentLogin: MSC4108SignInWithQR;
113112

114113
beforeEach(async () => {
115-
let ourData = defer<string>();
116-
let opponentData = defer<string>();
114+
let ourData = Promise.withResolvers<string>();
115+
let opponentData = Promise.withResolvers<string>();
117116

118117
const ourMockSession = {
119118
send: jest.fn(async (newData) => {
@@ -122,7 +121,7 @@ describe("MSC4108SignInWithQR", () => {
122121
receive: jest.fn(() => {
123122
const prom = opponentData.promise;
124123
prom.then(() => {
125-
opponentData = defer();
124+
opponentData = Promise.withResolvers();
126125
});
127126
return prom;
128127
}),
@@ -141,7 +140,7 @@ describe("MSC4108SignInWithQR", () => {
141140
receive: jest.fn(() => {
142141
const prom = ourData.promise;
143142
prom.then(() => {
144-
ourData = defer();
143+
ourData = Promise.withResolvers();
145144
});
146145
return prom;
147146
}),
@@ -334,11 +333,11 @@ describe("MSC4108SignInWithQR", () => {
334333
// @ts-ignore
335334
await opponentLogin.receive();
336335

337-
const deferred = defer<IMyDevice>();
338-
mocked(client.getDevice).mockReturnValue(deferred.promise);
336+
const deviceResolvers = Promise.withResolvers<IMyDevice>();
337+
mocked(client.getDevice).mockReturnValue(deviceResolvers.promise);
339338

340339
ourLogin.cancel(MSC4108FailureReason.UserCancelled).catch(() => {});
341-
deferred.resolve({} as IMyDevice);
340+
deviceResolvers.resolve({} as IMyDevice);
342341

343342
const secrets = {
344343
cross_signing: { master_key: "mk", user_signing_key: "usk", self_signing_key: "ssk" },

spec/integ/sliding-sync-sdk.spec.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ import { type SyncApiOptions, SyncState } from "../../src/sync";
4848
import { type IStoredClientOpts } from "../../src";
4949
import { logger } from "../../src/logger";
5050
import { emitPromise } from "../test-utils/test-utils";
51-
import { defer } from "../../src/utils";
5251
import { KnownMembership } from "../../src/@types/membership";
5352
import { type SyncCryptoCallbacks } from "../../src/common-crypto/CryptoBackend";
5453

@@ -369,7 +368,7 @@ describe("SlidingSyncSdk", () => {
369368
});
370369

371370
it("can be created with live events", async () => {
372-
const seenLiveEventDeferred = defer<boolean>();
371+
const seenLiveEventDeferred = Promise.withResolvers<boolean>();
373372
const listener = (
374373
ev: MatrixEvent,
375374
room?: Room,

spec/unit/ToDeviceMessageQueue.spec.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { getMockClientWithEventEmitter } from "../test-utils/client";
55
import { StubStore } from "../../src/store/stub";
66
import { type IndexedToDeviceBatch } from "../../src/models/ToDeviceMessage";
77
import { SyncState } from "../../src/sync";
8-
import { defer } from "../../src/utils";
98

109
describe("onResumedSync", () => {
1110
let batch: IndexedToDeviceBatch | null;
@@ -60,7 +59,7 @@ describe("onResumedSync", () => {
6059
});
6160

6261
it("resends queue after connectivity restored", async () => {
63-
const deferred = defer();
62+
const successResolvers = Promise.withResolvers<void>();
6463

6564
onSendToDeviceFailure = () => {
6665
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1);
@@ -73,31 +72,31 @@ describe("onResumedSync", () => {
7372
onSendToDeviceSuccess = () => {
7473
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(3);
7574
expect(store.removeToDeviceBatch).toHaveBeenCalled();
76-
deferred.resolve();
75+
successResolvers.resolve();
7776
};
7877

7978
queue.start();
80-
return deferred.promise;
79+
return successResolvers.promise;
8180
});
8281

8382
it("does not resend queue if client sync still catching up", async () => {
84-
const deferred = defer();
83+
const successResolvers = Promise.withResolvers<void>();
8584

8685
onSendToDeviceFailure = () => {
8786
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1);
8887
expect(store.removeToDeviceBatch).not.toHaveBeenCalled();
8988

9089
resumeSync(SyncState.Catchup, SyncState.Catchup);
9190
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1);
92-
deferred.resolve();
91+
successResolvers.resolve();
9392
};
9493

9594
queue.start();
96-
return deferred.promise;
95+
return successResolvers.promise;
9796
});
9897

9998
it("does not resend queue if connectivity restored after queue stopped", async () => {
100-
const deferred = defer();
99+
const successResolvers = Promise.withResolvers<void>();
101100

102101
onSendToDeviceFailure = () => {
103102
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1);
@@ -107,10 +106,10 @@ describe("onResumedSync", () => {
107106

108107
resumeSync(SyncState.Syncing, SyncState.Catchup);
109108
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1);
110-
deferred.resolve();
109+
successResolvers.resolve();
111110
};
112111

113112
queue.start();
114-
return deferred.promise;
113+
return successResolvers.promise;
115114
});
116115
});

0 commit comments

Comments
 (0)