Skip to content

Commit 589938f

Browse files
committed
Merge tag 'v23.5.0' into sc
* Implement MSC3758: a push rule condition to match event properties exactly ([\matrix-org#3179](matrix-org#3179)). * Enable group calls without video and audio track by configuration of MatrixClient ([\matrix-org#3162](matrix-org#3162)). Contributed by @EnricoSchw. * Updates to protocol used for Sign in with QR code ([\matrix-org#3155](matrix-org#3155)). Contributed by @hughns. * Implement MSC3873 to handle escaped dots in push rule keys ([\matrix-org#3134](matrix-org#3134)). Fixes undefined/matrix-js-sdk#1454. * Fix spec compliance issue around encrypted `m.relates_to` ([\matrix-org#3178](matrix-org#3178)). * Fix reactions in threads sometimes causing stuck notifications ([\matrix-org#3146](matrix-org#3146)). Fixes element-hq/element-web#24000. Contributed by @justjanne.
2 parents 0c0854b + 26663e6 commit 589938f

31 files changed

+1923
-793
lines changed

.github/workflows/docs-pr-netlify.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
# There's a 'download artifact' action, but it hasn't been updated for the workflow_run action
1515
# (https://github.com/actions/download-artifact/issues/60) so instead we get this mess:
1616
- name: 📥 Download artifact
17-
uses: dawidd6/action-download-artifact@bd10f381a96414ce2b13a11bfa89902ba7cea07f # v2.24.3
17+
uses: dawidd6/action-download-artifact@5e780fc7bbd0cac69fc73271ed86edf5dcb72d67 # v2.26.0
1818
with:
1919
workflow: static_analysis.yml
2020
run_id: ${{ github.event.workflow_run.id }}

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ out
1919

2020
.vscode
2121
.vscode/
22+
.idea/

CHANGELOG.md

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
Changes in [23.5.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v23.5.0) (2023-03-15)
2+
==================================================================================================
3+
4+
## ✨ Features
5+
* Implement MSC3758: a push rule condition to match event properties exactly ([\#3179](https://github.com/matrix-org/matrix-js-sdk/pull/3179)).
6+
* Enable group calls without video and audio track by configuration of MatrixClient ([\#3162](https://github.com/matrix-org/matrix-js-sdk/pull/3162)). Contributed by @EnricoSchw.
7+
* Updates to protocol used for Sign in with QR code ([\#3155](https://github.com/matrix-org/matrix-js-sdk/pull/3155)). Contributed by @hughns.
8+
* Implement MSC3873 to handle escaped dots in push rule keys ([\#3134](https://github.com/matrix-org/matrix-js-sdk/pull/3134)). Fixes undefined/matrix-js-sdk#1454.
9+
10+
## 🐛 Bug Fixes
11+
* Fix spec compliance issue around encrypted `m.relates_to` ([\#3178](https://github.com/matrix-org/matrix-js-sdk/pull/3178)).
12+
* Fix reactions in threads sometimes causing stuck notifications ([\#3146](https://github.com/matrix-org/matrix-js-sdk/pull/3146)). Fixes vector-im/element-web#24000. Contributed by @justjanne.
13+
114
Changes in [23.4.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v23.4.0) (2023-02-28)
215
==================================================================================================
316

@@ -7,8 +20,6 @@ Changes in [23.4.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v23
720
* Polls: count undecryptable poll relations ([\#3163](https://github.com/matrix-org/matrix-js-sdk/pull/3163)). Contributed by @kerryarchibald.
821

922
## 🐛 Bug Fixes
10-
* Fix spec compliance issue around encrypted `m.relates_to` ([\#3178](https://github.com/matrix-org/matrix-js-sdk/pull/3178)).
11-
* Fix reactions in threads sometimes causing stuck notifications ([\#3146](https://github.com/matrix-org/matrix-js-sdk/pull/3146)). Fixes vector-im/element-web#24000. Contributed by @justjanne.
1223
* Better type guard parseTopicContent ([\#3165](https://github.com/matrix-org/matrix-js-sdk/pull/3165)). Fixes matrix-org/element-web-rageshakes#20177 and matrix-org/element-web-rageshakes#20178.
1324
* Fix a bug where events in encrypted rooms would sometimes erroneously increment the total unread counter after being processed locally. ([\#3130](https://github.com/matrix-org/matrix-js-sdk/pull/3130)). Fixes vector-im/element-web#24448. Contributed by @Half-Shot.
1425
* Stop the ICE disconnected timer on call terminate ([\#3147](https://github.com/matrix-org/matrix-js-sdk/pull/3147)).

package.json

+26-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "matrix-js-sdk",
3-
"version": "23.4.0",
3+
"version": "23.5.0",
44
"description": "Matrix Client-Server SDK for Javascript",
55
"engines": {
66
"node": ">=16.0.0"
@@ -14,7 +14,7 @@
1414
"build:dev": "yarn clean && git rev-parse HEAD > git-revision.txt && yarn build:compile && yarn build:types",
1515
"build:types": "tsc -p tsconfig-build.json --emitDeclarationOnly",
1616
"build:compile": "babel -d lib --verbose --extensions \".ts,.js\" src",
17-
"build:compile-browser": "mkdir dist && browserify -d src/browser-index.ts -p [ tsify -p ./tsconfig-build.json ] -t [ babelify --sourceMaps=inline --presets [ @babel/preset-env @babel/preset-typescript ] ] | exorcist dist/browser-matrix.js.map > dist/browser-matrix.js",
17+
"build:compile-browser": "mkdir dist && BROWSERIFYSWAP_ENV='no-rust-crypto' browserify -d src/browser-index.ts -p [ tsify -p ./tsconfig-build.json ] | exorcist dist/browser-matrix.js.map > dist/browser-matrix.js",
1818
"build:minify-browser": "terser dist/browser-matrix.js --compress --mangle --source-map --output dist/browser-matrix.min.js",
1919
"gendoc": "typedoc",
2020
"lint": "yarn lint:types && yarn lint:js",
@@ -97,16 +97,17 @@
9797
"babelify": "^10.0.0",
9898
"better-docs": "^2.4.0-beta.9",
9999
"browserify": "^17.0.0",
100+
"browserify-swap": "^0.2.2",
100101
"debug": "^4.3.4",
101102
"docdash": "^2.0.0",
102103
"domexception": "^4.0.0",
103-
"eslint": "8.33.0",
104+
"eslint": "8.34.0",
104105
"eslint-config-google": "^0.14.0",
105106
"eslint-config-prettier": "^8.5.0",
106107
"eslint-import-resolver-typescript": "^3.5.1",
107108
"eslint-plugin-import": "^2.26.0",
108109
"eslint-plugin-jest": "^27.1.6",
109-
"eslint-plugin-jsdoc": "^39.6.4",
110+
"eslint-plugin-jsdoc": "^40.0.0",
110111
"eslint-plugin-matrix-org": "^1.0.0",
111112
"eslint-plugin-tsdoc": "^0.2.17",
112113
"eslint-plugin-unicorn": "^45.0.0",
@@ -118,7 +119,7 @@
118119
"jest-localstorage-mock": "^2.4.6",
119120
"jest-mock": "^29.0.0",
120121
"matrix-mock-request": "^2.5.0",
121-
"prettier": "2.8.3",
122+
"prettier": "2.8.4",
122123
"rimraf": "^4.0.0",
123124
"terser": "^5.5.1",
124125
"tsify": "^5.0.2",
@@ -148,5 +149,25 @@
148149
"outputName": "jest-sonar-report.xml",
149150
"relativePaths": true
150151
},
152+
"browserify": {
153+
"transform": [
154+
"browserify-swap",
155+
[
156+
"babelify",
157+
{
158+
"sourceMaps": "inline",
159+
"presets": [
160+
"@babel/preset-env",
161+
"@babel/preset-typescript"
162+
]
163+
}
164+
]
165+
]
166+
},
167+
"browserify-swap": {
168+
"no-rust-crypto": {
169+
"src/rust-crypto/index.ts$": "./src/rust-crypto/browserify-index.ts"
170+
}
171+
},
151172
"typings": "./lib/index.d.ts"
152173
}

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

+9-2
Original file line numberDiff line numberDiff line change
@@ -1336,18 +1336,25 @@ describe("MatrixClient", function () {
13361336
it.each([
13371337
{
13381338
userId: "alice@localhost",
1339+
powerLevel: 100,
13391340
expectation: {
13401341
"alice@localhost": 100,
13411342
},
13421343
},
13431344
{
13441345
userId: ["alice@localhost", "bob@localhost"],
1346+
powerLevel: 100,
13451347
expectation: {
13461348
"alice@localhost": 100,
13471349
"bob@localhost": 100,
13481350
},
13491351
},
1350-
])("should modify power levels of $userId correctly", async ({ userId, expectation }) => {
1352+
{
1353+
userId: "alice@localhost",
1354+
powerLevel: undefined,
1355+
expectation: {},
1356+
},
1357+
])("should modify power levels of $userId correctly", async ({ userId, powerLevel, expectation }) => {
13511358
const event = {
13521359
getType: () => "m.room.power_levels",
13531360
getContent: () => ({
@@ -1364,7 +1371,7 @@ describe("MatrixClient", function () {
13641371
})
13651372
.respond(200, {});
13661373

1367-
const prom = client!.setPowerLevel("!room_id:server", userId, 100, event);
1374+
const prom = client!.setPowerLevel("!room_id:server", userId, powerLevel, event);
13681375
await httpBackend!.flushAllExpected();
13691376
await prom;
13701377
});

spec/integ/matrix-client-unread-notifications.spec.ts

+94-1
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,21 @@ import "fake-indexeddb/auto";
1818

1919
import HttpBackend from "matrix-mock-request";
2020

21-
import { Category, ISyncResponse, MatrixClient, NotificationCountType, Room } from "../../src";
21+
import {
22+
Category,
23+
ClientEvent,
24+
EventType,
25+
ISyncResponse,
26+
MatrixClient,
27+
MatrixEvent,
28+
NotificationCountType,
29+
RelationType,
30+
Room,
31+
} from "../../src";
2232
import { TestClient } from "../TestClient";
33+
import { ReceiptType } from "../../src/@types/read_receipts";
34+
import { mkThread } from "../test-utils/thread";
35+
import { SyncState } from "../../src/sync";
2336

2437
describe("MatrixClient syncing", () => {
2538
const userA = "@alice:localhost";
@@ -51,6 +64,86 @@ describe("MatrixClient syncing", () => {
5164
return httpBackend!.stop();
5265
});
5366

67+
it("reactions in thread set the correct timeline to unread", async () => {
68+
const roomId = "!room:localhost";
69+
70+
// start the client, and wait for it to initialise
71+
httpBackend!.when("GET", "/sync").respond(200, {
72+
next_batch: "s_5_3",
73+
rooms: {
74+
[Category.Join]: {},
75+
[Category.Leave]: {},
76+
[Category.Invite]: {},
77+
},
78+
});
79+
client!.startClient({ threadSupport: true });
80+
await Promise.all([
81+
httpBackend?.flushAllExpected(),
82+
new Promise<void>((resolve) => {
83+
client!.on(ClientEvent.Sync, (state) => state === SyncState.Syncing && resolve());
84+
}),
85+
]);
86+
87+
const room = new Room(roomId, client!, selfUserId);
88+
jest.spyOn(client!, "getRoom").mockImplementation((id) => (id === roomId ? room : null));
89+
90+
const thread = mkThread({ room, client: client!, authorId: selfUserId, participantUserIds: [selfUserId] });
91+
const threadReply = thread.events.at(-1)!;
92+
room.addLiveEvents([thread.rootEvent]);
93+
94+
// Initialize read receipt datastructure before testing the reaction
95+
room.addReceiptToStructure(thread.rootEvent.getId()!, ReceiptType.Read, selfUserId, { ts: 1 }, false);
96+
thread.thread.addReceiptToStructure(
97+
threadReply.getId()!,
98+
ReceiptType.Read,
99+
selfUserId,
100+
{ thread_id: thread.thread.id, ts: 1 },
101+
false,
102+
);
103+
expect(room.getReadReceiptForUserId(selfUserId, false)?.eventId).toEqual(thread.rootEvent.getId());
104+
expect(thread.thread.getReadReceiptForUserId(selfUserId, false)?.eventId).toEqual(threadReply.getId());
105+
106+
const reactionEventId = `$9-${Math.random()}-${Math.random()}`;
107+
let lastEvent: MatrixEvent | null = null;
108+
jest.spyOn(client! as any, "sendEventHttpRequest").mockImplementation((event) => {
109+
lastEvent = event as MatrixEvent;
110+
return { event_id: reactionEventId };
111+
});
112+
113+
await client!.sendEvent(roomId, EventType.Reaction, {
114+
"m.relates_to": {
115+
rel_type: RelationType.Annotation,
116+
event_id: threadReply.getId(),
117+
key: "",
118+
},
119+
});
120+
121+
expect(lastEvent!.getId()).toEqual(reactionEventId);
122+
room.handleRemoteEcho(new MatrixEvent(lastEvent!.event), lastEvent!);
123+
124+
// Our ideal state after this is the following:
125+
//
126+
// Room: [synthetic: threadroot, actual: threadroot]
127+
// Thread: [synthetic: threadreaction, actual: threadreply]
128+
//
129+
// The reaction and reply are both in the thread, and their receipts should be isolated to the thread.
130+
// The reaction has not been acknowledged in a dedicated read receipt message, so only the synthetic receipt
131+
// should be updated.
132+
133+
// Ensure the synthetic receipt for the room has not been updated
134+
expect(room.getReadReceiptForUserId(selfUserId, false)?.eventId).toEqual(thread.rootEvent.getId());
135+
expect(room.getEventReadUpTo(selfUserId, false)).toEqual(thread.rootEvent.getId());
136+
// Ensure the actual receipt for the room has not been updated
137+
expect(room.getReadReceiptForUserId(selfUserId, true)?.eventId).toEqual(thread.rootEvent.getId());
138+
expect(room.getEventReadUpTo(selfUserId, true)).toEqual(thread.rootEvent.getId());
139+
// Ensure the synthetic receipt for the thread has been updated
140+
expect(thread.thread.getReadReceiptForUserId(selfUserId, false)?.eventId).toEqual(reactionEventId);
141+
expect(thread.thread.getEventReadUpTo(selfUserId, false)).toEqual(reactionEventId);
142+
// Ensure the actual receipt for the thread has not been updated
143+
expect(thread.thread.getReadReceiptForUserId(selfUserId, true)?.eventId).toEqual(threadReply.getId());
144+
expect(thread.thread.getEventReadUpTo(selfUserId, true)).toEqual(threadReply.getId());
145+
});
146+
54147
describe("Stuck unread notifications integration tests", () => {
55148
const ROOM_ID = "!room:localhost";
56149

0 commit comments

Comments
 (0)