Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support MSC4222 state_after #4487

Merged
merged 40 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
6df4fc6
WIP support for state_after
dbkr Oct 30, 2024
80905ad
Fix sliding sync sdk / embedded tests
dbkr Oct 30, 2024
94ea7b5
Allow both state & state_after to be undefined
dbkr Oct 31, 2024
542d95e
Fix limited sync handling
dbkr Oct 31, 2024
648019b
Need to use state_after being undefined
dbkr Oct 31, 2024
08baeb8
Make sliding sync sdk tests pass
dbkr Oct 31, 2024
81665c7
Remove deprecated interfaces & backwards-compat code
dbkr Oct 31, 2024
53506b8
Remove useless assignment
hughns Nov 1, 2024
84c873c
Use updates unstable prefix
hughns Nov 1, 2024
a514b1f
Clarify docs
hughns Nov 1, 2024
82ba72b
Remove additional semi-backwards compatible overload
hughns Nov 1, 2024
04f5a77
Merge branch 'develop' into dbkr/stateafter
hughns Nov 4, 2024
4ed11ce
Update unstable prefixes
hughns Nov 4, 2024
34f6613
Iterate
t3chguy Nov 6, 2024
f499163
Iterate
t3chguy Nov 6, 2024
6ce0087
Fix test
t3chguy Nov 6, 2024
5ecc312
Iterate
t3chguy Nov 6, 2024
d414222
Merge branch 'develop' into dbkr/stateafter
t3chguy Nov 6, 2024
f010962
Merge remote-tracking branch 'origin/dbkr/stateafter' into dbkr/state…
t3chguy Nov 8, 2024
f8574e9
Iterate
t3chguy Nov 8, 2024
c387132
Add test for MSC4222 behaviour
t3chguy Nov 8, 2024
9605132
Improve coverage
t3chguy Nov 8, 2024
e1746c5
Iterate
t3chguy Nov 8, 2024
d61d16c
Fix tests
t3chguy Nov 8, 2024
e4d5e6b
Iterate
t3chguy Nov 8, 2024
f10deb5
Tidy
t3chguy Nov 8, 2024
ad4f629
Merge branch 'develop' into dbkr/stateafter
t3chguy Nov 8, 2024
7c24d66
Add comments to explain why things work as they are.
toger5 Nov 12, 2024
03e690e
Merge branch 'develop' into dbkr/stateafter
t3chguy Nov 12, 2024
58d0edd
Fix sync accumulator for state_after sync handling
t3chguy Nov 12, 2024
a1e69b6
Merge remote-tracking branch 'origin/dbkr/stateafter' into dbkr/state…
t3chguy Nov 12, 2024
d290bc4
Add tests
t3chguy Nov 13, 2024
23f9934
Revert "Fix room state being updated with old (now overwritten) state…
toger5 Nov 15, 2024
28fd0c0
Fix Sync Accumulator toJSON putting start timeline state in state_aft…
t3chguy Nov 19, 2024
80582a7
Merge branch 'develop' of github.com:matrix-org/matrix-js-sdk into db…
t3chguy Nov 19, 2024
7f1440b
Update tests
t3chguy Nov 20, 2024
3b09233
Add test case
t3chguy Nov 20, 2024
cc507ea
Iterate
t3chguy Nov 20, 2024
f38f106
Merge branch 'develop' into dbkr/stateafter
t3chguy Nov 27, 2024
2c48b3c
Merge branch 'develop' into dbkr/stateafter
t3chguy Nov 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions spec/integ/crypto/crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1327,7 +1327,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,

const syncResponse = getSyncResponse(["@bob:xyz"]);
// Every 2 messages in the room, the session should be rotated
syncResponse.rooms[Category.Join][ROOM_ID].state.events[0].content = {
syncResponse.rooms[Category.Join][ROOM_ID].state!.events[0].content = {
algorithm: "m.megolm.v1.aes-sha2",
rotation_period_msgs: 2,
};
Expand Down Expand Up @@ -1383,7 +1383,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
const oneHourInMs = 60 * 60 * 1000;

// Every 1h the session should be rotated
syncResponse.rooms[Category.Join][ROOM_ID].state.events[0].content = {
syncResponse.rooms[Category.Join][ROOM_ID].state!.events[0].content = {
algorithm: "m.megolm.v1.aes-sha2",
rotation_period_ms: oneHourInMs,
};
Expand Down
12 changes: 6 additions & 6 deletions spec/integ/matrix-client-event-timeline.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1144,7 +1144,7 @@ describe("MatrixClient event timelines", function () {

const prom = emitPromise(room, ThreadEvent.Update);
// Assume we're seeing the reply while loading backlog
await room.addLiveEvents([THREAD_REPLY2]);
await room.addLiveEvents([THREAD_REPLY2], { addToState: false });
httpBackend
.when(
"GET",
Expand All @@ -1155,7 +1155,7 @@ describe("MatrixClient event timelines", function () {
});
await flushHttp(prom);
// but while loading the metadata, a new reply has arrived
await room.addLiveEvents([THREAD_REPLY3]);
await room.addLiveEvents([THREAD_REPLY3], { addToState: false });
const thread = room.getThread(THREAD_ROOT_UPDATED.event_id!)!;
// then the events should still be all in the right order
expect(thread.events.map((it) => it.getId())).toEqual([
Expand Down Expand Up @@ -1247,7 +1247,7 @@ describe("MatrixClient event timelines", function () {

const prom = emitPromise(room, ThreadEvent.Update);
// Assume we're seeing the reply while loading backlog
await room.addLiveEvents([THREAD_REPLY2]);
await room.addLiveEvents([THREAD_REPLY2], { addToState: false });
httpBackend
.when(
"GET",
Expand All @@ -1263,7 +1263,7 @@ describe("MatrixClient event timelines", function () {
});
await flushHttp(prom);
// but while loading the metadata, a new reply has arrived
await room.addLiveEvents([THREAD_REPLY3]);
await room.addLiveEvents([THREAD_REPLY3], { addToState: false });
const thread = room.getThread(THREAD_ROOT_UPDATED.event_id!)!;
// then the events should still be all in the right order
expect(thread.events.map((it) => it.getId())).toEqual([
Expand Down Expand Up @@ -1560,7 +1560,7 @@ describe("MatrixClient event timelines", function () {
thread.initialEventsFetched = true;
const prom = emitPromise(room, ThreadEvent.NewReply);
respondToEvent(THREAD_ROOT_UPDATED);
await room.addLiveEvents([THREAD_REPLY2]);
await room.addLiveEvents([THREAD_REPLY2], { addToState: false });
await httpBackend.flushAllExpected();
await prom;
expect(thread.length).toBe(2);
Expand Down Expand Up @@ -1685,7 +1685,7 @@ describe("MatrixClient event timelines", function () {
thread.initialEventsFetched = true;
const prom = emitPromise(room, ThreadEvent.Update);
respondToEvent(THREAD_ROOT_UPDATED);
await room.addLiveEvents([THREAD_REPLY_REACTION]);
await room.addLiveEvents([THREAD_REPLY_REACTION], { addToState: false });
await httpBackend.flushAllExpected();
await prom;
expect(thread.length).toBe(1); // reactions don't count towards the length of a thread
Expand Down
57 changes: 33 additions & 24 deletions spec/integ/matrix-client-methods.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,14 +168,17 @@ describe("MatrixClient", function () {
type: "test",
content: {},
});
room.addLiveEvents([
utils.mkMembership({
user: userId,
room: roomId,
mship: KnownMembership.Join,
event: true,
}),
]);
room.addLiveEvents(
[
utils.mkMembership({
user: userId,
room: roomId,
mship: KnownMembership.Join,
event: true,
}),
],
{ addToState: true },
);
httpBackend.verifyNoOutstandingRequests();
store.storeRoom(room);

Expand All @@ -188,14 +191,17 @@ describe("MatrixClient", function () {
const roomId = "!roomId:server";
const roomAlias = "#my-fancy-room:server";
const room = new Room(roomId, client, userId);
room.addLiveEvents([
utils.mkMembership({
user: userId,
room: roomId,
mship: KnownMembership.Join,
event: true,
}),
]);
room.addLiveEvents(
[
utils.mkMembership({
user: userId,
room: roomId,
mship: KnownMembership.Join,
event: true,
}),
],
{ addToState: true },
);
store.storeRoom(room);

// The method makes a request to resolve the alias
Expand Down Expand Up @@ -275,14 +281,17 @@ describe("MatrixClient", function () {
content: {},
});

room.addLiveEvents([
utils.mkMembership({
user: userId,
room: roomId,
mship: KnownMembership.Knock,
event: true,
}),
]);
room.addLiveEvents(
[
utils.mkMembership({
user: userId,
room: roomId,
mship: KnownMembership.Knock,
event: true,
}),
],
{ addToState: true },
);

httpBackend.verifyNoOutstandingRequests();
store.storeRoom(room);
Expand Down
167 changes: 163 additions & 4 deletions spec/integ/matrix-client-syncing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ describe("MatrixClient syncing", () => {
});

it("should resolve incoming invites from /sync", () => {
syncData.rooms.join[roomOne].state.events.push(
syncData.rooms.join[roomOne].state!.events.push(
utils.mkMembership({
room: roomOne,
mship: KnownMembership.Invite,
Expand Down Expand Up @@ -589,7 +589,7 @@ describe("MatrixClient syncing", () => {
name: "The Ghost",
}) as IMinimalEvent,
];
syncData.rooms.join[roomOne].state.events.push(
syncData.rooms.join[roomOne].state!.events.push(
utils.mkMembership({
room: roomOne,
mship: KnownMembership.Invite,
Expand Down Expand Up @@ -617,7 +617,7 @@ describe("MatrixClient syncing", () => {
name: "The Ghost",
}) as IMinimalEvent,
];
syncData.rooms.join[roomOne].state.events.push(
syncData.rooms.join[roomOne].state!.events.push(
utils.mkMembership({
room: roomOne,
mship: KnownMembership.Invite,
Expand All @@ -644,7 +644,7 @@ describe("MatrixClient syncing", () => {
});

it("should no-op if resolveInvitesToProfiles is not set", () => {
syncData.rooms.join[roomOne].state.events.push(
syncData.rooms.join[roomOne].state!.events.push(
utils.mkMembership({
room: roomOne,
mship: KnownMembership.Invite,
Expand Down Expand Up @@ -1373,6 +1373,114 @@ describe("MatrixClient syncing", () => {
expect(stateEventEmitCount).toEqual(2);
});
});

describe("msc4222", () => {
const roomOneSyncOne = {
"timeline": {
events: [
utils.mkMessage({
room: roomOne,
user: otherUserId,
msg: "hello",
}),
],
},
"org.matrix.msc4222.state_after": {
events: [
utils.mkEvent({
type: "m.room.name",
room: roomOne,
user: otherUserId,
content: {
name: "Initial room name",
},
}),
utils.mkMembership({
room: roomOne,
mship: KnownMembership.Join,
user: otherUserId,
}),
utils.mkMembership({
room: roomOne,
mship: KnownMembership.Join,
user: selfUserId,
}),
utils.mkEvent({
type: "m.room.create",
room: roomOne,
user: selfUserId,
content: {},
}),
],
},
};
const roomOneSyncTwo = {
"org.matrix.msc4222.state_after": {
events: [
utils.mkEvent({
type: "m.room.topic",
room: roomOne,
user: selfUserId,
content: { topic: "A new room topic" },
}),
],
},
"state": {
events: [
utils.mkEvent({
type: "m.room.name",
room: roomOne,
user: selfUserId,
content: { name: "A new room name" },
}),
],
},
};

it("should ignore state events in timeline when state_after is present", async () => {
httpBackend!.when("GET", "/sync").respond(200, {
rooms: {
join: { [roomOne]: roomOneSyncOne },
},
});
httpBackend!.when("GET", "/sync").respond(200, {
rooms: {
join: { [roomOne]: roomOneSyncTwo },
},
});

client!.startClient();
return Promise.all([httpBackend!.flushAllExpected(), awaitSyncEvent(2)]).then(() => {
const room = client!.getRoom(roomOne)!;
expect(room.name).toEqual("Initial room name");
expect(room.currentState.getStateEvents("m.room.topic", "")?.getContent().topic).toBe(
"A new room topic",
);
});
});

it("should respect state events in state_after for left rooms", async () => {
httpBackend!.when("GET", "/sync").respond(200, {
rooms: {
join: { [roomOne]: roomOneSyncOne },
},
});
httpBackend!.when("GET", "/sync").respond(200, {
rooms: {
leave: { [roomOne]: roomOneSyncTwo },
},
});

client!.startClient();
return Promise.all([httpBackend!.flushAllExpected(), awaitSyncEvent(2)]).then(() => {
const room = client!.getRoom(roomOne)!;
expect(room.name).toEqual("Initial room name");
expect(room.currentState.getStateEvents("m.room.topic", "")?.getContent().topic).toBe(
"A new room topic",
);
});
});
});
});

describe("timeline", () => {
Expand Down Expand Up @@ -2274,6 +2382,57 @@ describe("MatrixClient syncing", () => {
}),
]);
});

describe("msc4222", () => {
it("should respect state events in state_after for left rooms", async () => {
httpBackend!.when("POST", "/filter").respond(200, {
filter_id: "another_id",
});

httpBackend!.when("GET", "/sync").respond(200, {
rooms: {
leave: {
[roomOne]: {
"org.matrix.msc4222.state_after": {
events: [
utils.mkEvent({
type: "m.room.topic",
room: roomOne,
user: selfUserId,
content: { topic: "A new room topic" },
}),
],
},
"state": {
events: [
utils.mkEvent({
type: "m.room.name",
room: roomOne,
user: selfUserId,
content: { name: "A new room name" },
}),
],
},
},
},
},
});

const [[room]] = await Promise.all([
client!.syncLeftRooms(),

// first flush the filter request; this will make syncLeftRooms make its /sync call
httpBackend!.flush("/filter").then(() => {
return httpBackend!.flushAllExpected();
}),
]);

expect(room.name).toEqual("Empty room");
expect(room.currentState.getStateEvents("m.room.topic", "")?.getContent().topic).toBe(
"A new room topic",
);
});
});
});

describe("peek", () => {
Expand Down
2 changes: 1 addition & 1 deletion spec/integ/matrix-client-unread-notifications.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ describe("MatrixClient syncing", () => {

const thread = mkThread({ room, client: client!, authorId: selfUserId, participantUserIds: [selfUserId] });
const threadReply = thread.events.at(-1)!;
await room.addLiveEvents([thread.rootEvent]);
await room.addLiveEvents([thread.rootEvent], { addToState: false });

// Initialize read receipt datastructure before testing the reaction
room.addReceiptToStructure(thread.rootEvent.getId()!, ReceiptType.Read, selfUserId, { ts: 1 }, false);
Expand Down
Loading