From d156cb97fd8f731d4cdfa86a56618c6285899677 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Fri, 12 Sep 2025 10:06:21 +0100 Subject: [PATCH] Change the required_state request format --- proposals/4186-simplified-sliding-sync.md | 123 +++++++++++----------- 1 file changed, 62 insertions(+), 61 deletions(-) diff --git a/proposals/4186-simplified-sliding-sync.md b/proposals/4186-simplified-sliding-sync.md index c112793df..98c64370d 100644 --- a/proposals/4186-simplified-sliding-sync.md +++ b/proposals/4186-simplified-sliding-sync.md @@ -248,7 +248,7 @@ The endpoint is a `POST` request with a JSON body to `/_matrix/client/unstable/o | Name | Type | Required | Comment | | - | - | - | - | | `timeline_limit` | `int` | Yes | The maximum number of timeline events to return per response. The server may cap this number. | -| `required_state` | [RequiredStateTuple] | Yes | Required state for each room returned. | +| `required_state` | [RequiredStateRequest] | Yes | Required state for each room returned. | | `ranges` | `[[int, int]]` | No | Sliding window ranges. If this field is missing, no sliding window is used and all rooms are returned in this list. Integers are *inclusive*. (This is a list of 2-tuples.) | | `filters` | `RoomFilter` | No | Filters to apply to the list before sorting. | @@ -257,65 +257,33 @@ The endpoint is a `POST` request with a JSON body to `/_matrix/client/unstable/o | Name | Type | Required | Comment | | - | - | - | - | | `timeline_limit` | `int` | Yes | Same as in `SyncListConfig` | -| `required_state` | [RequiredStateTuple] | Yes | Same as in `SyncListConfig` | +| `required_state` | [RequiredStateRequest] | Yes | Same as in `SyncListConfig` | -### `RequiredStateTuple` +### `RequiredStateRequest` -An array of event type and state key tuples. Elements in this array are ORd together to produce the final set of state -events to return. +Describes the set of state that the server should return for the room. -For example, the following would return the create event and current power levels: - -```jsonc - { - "required_state": [ - ["m.room.create", ""], - ["m.room.power_levels", ""] - ] - } -``` - - -#### Special values - -There are a number of special values that the client can use in place of either the event type or state key: +| Name | Type | Required | Comment | +| - | - | - | - | +| `include` | `[RequiredStateElement]` | Yes | The set of state to return (unless filtered out by `exclude`). | +| `exclude` | `[RequiredStateElement]` | No | The set of state to filter out before returning, if any. | +| `lazy_members` | `bool` | No | Whether to enable lazy loaded membership behaviour. Defaults to false. | -1. `"*"` — Can be used in either the type or state key position to match any type or state key. -1. `"$LAZY"` — Can be used in the state key position when the type is `m.room.member`. This triggers the lazy loading - membership behaviour (as in sync v2), described in the next sections. -1. `"$ME"` — Can be used in the state key position to match the user's full user ID. This is merely a convenience for - clients, and has the same semantics as if the client used the full user ID (e.g. `"@user:example.com"`). -#### Wildcards +#### `RequiredStateElement` -The wildcard (`"*"`) can be used in either the type or state key position, and matches any type or state key. The client -can use `["*", "*"]` to request all state. +| Name | Type | Required | Comment | +| - | - | - | - | +| `type` | `string` | No | The event type to match. If omitted then matches all types. | +| `state_key` | `string` | No | The event state key to match. If omitted then matches all state keys. | -There is a special case when `["*", "*"]` is used with additional entries: the additional entries are FILTERED OUT the -of the returned set of state events. These additional entries cannot use `*` themselves. For example, `["*", "*"], -["m.room.member", "@alice:example.com"]` will *exclude* every `m.room.member` event *except* for `@alice:example.com`, -and include every other state event. In addition, `["*", "*"], ["m.space.child", "*"]` is an error, the `m.space.child` -filter is not required as it would have been returned anyway. -> [!Note] -> Synapse doesn't currently support filtering out state, and simply returns all state. #### Lazy loaded memberships -Room members can be lazily-loaded by using the special `$LAZY` state key (`["m.room.member", "$LAZY"]`). Typically, when -you view a room, you want to retrieve all state events except for m.room.member events which you want to lazily load. To -get this behaviour, clients can send the following: - -```jsonc - { - "required_state": [ - // activate lazy loading - ["m.room.member", "$LAZY"], - // request all state events _except_ for m.room.member events which are lazily loaded - ["*", "*"] - ] - } -``` +Room members can be lazily-loaded by using the `lazy_members` flag is set. Typically, when you view a room, you want to +retrieve all state events except for m.room.member events which you want to lazily load. To get this behaviour, clients +can send the following: This is (almost) the same as lazy loaded memberships in sync v2. When specified, the server will return the membership events for: @@ -326,12 +294,41 @@ events for: cache the membership list without requiring the server to send all membership updates for large gaps. +Memberships returned to the client due to `lazy_members` are *not* filtered by `exclude`. + + #### Combining `required_state` -When combining room configs with different `required_state` fields the result must be the superset of the different sets -of `required_state`. There are two approaches server-side for handling this: a) keep the `required_state` sets -separates and return any state that matches any set, or b) merge the sets together, however care must be taken to -correctly account for wildcards, i.e. one cannot simply join the lists together. +When combining room configs with different `required_state` fields the result must be the superset of them all. There +are two approaches server-side for handling this: a) keep the `required_state` separate and return any state that +matches any of them, or b) merge the fields together, however care must be taken to correctly account for wildcards. + +#### Examples + +Simple example that returns the create event and power levels: + +```jsonc + { + "required_state": { + "include": [ + {"type": "m.room.create", "state_key": ""}, + {"type": "m.room.power_levels", "state_key": ""}, + ], + } + } +``` + +An example that returns all the state except the create event: + +```jsonc + { + "required_state": { + "include": [{}], // An empty object matches everything + "exclude": [{"type": "m.room.create", "state_key": ""}] + } + } +``` + ### `RoomFilter` @@ -358,10 +355,12 @@ correctly account for wildcards, i.e. one cannot simply join the lists together. "lists": { "foo-list": { "ranges": [ [0, 99] ], - "required_state": [ - ["m.room.create", ""], - ["m.room.member", "$LAZY"], - ], + "required_state": { + "include": [ + {"type": "m.room.create", "state_key": ""}, + ], + "lazy_members": true, + }, "timeline_limit": 10, "filters": { "is_dm": true @@ -371,7 +370,7 @@ correctly account for wildcards, i.e. one cannot simply join the lists together. // Room Subscriptions API "room_subscriptions": { "!sub1:bar": { - "required_state": [ ["*","*"] ], + "required_state": { "include": [{}] }, "timeline_limit": 10, } } @@ -625,9 +624,9 @@ in `/_matrix/client/versions` is `org.matrix.simplified_msc3575`. 1. We need to decide what to do with `unstable_expanded_timeline`. We can either rename it to `expanded_timeline`, or remove the functionality and replace it with a bulk `/messages` endpoint (for multiple rooms). See "Timeline event trickling" section. -1. The request `required_state` field is a bit confusing and uses special strings (like `"*"` and `"$LAZY"`). -1. Duplication between room response `heroes` and `required_state` when specifying `["m.room.member", "$LAZY"]`, e.g. - should we drop `heroes` if we are returning membership events? +1. The request `required_state` field is a bit confusing and uses special strings (like `"*"` and `"$LAZY"`). +1. Duplication between room response `heroes` and `required_state` when specifying `lazy_members`, e.g. should we drop + `heroes` if we are returning membership events? 1. Should the room response include the user's current membership? The client can always request it via `required_state`, but that may be wasted if the client doesn't need any other information from the member event. 1. Should we remove the `highlight_count` and `notification_count` fields, given clients increasingly must calculate @@ -636,6 +635,7 @@ in `/_matrix/client/versions` is `org.matrix.simplified_msc3575`. 1. Should we support timeline filtering? 1. Should we move `pos`, and other URL params, into the request body? This would allow web clients to cache the CORS requests, rather than having to pre-flight each request. +1. How do we make it so that the clients don't have to send up the same body each time? ## TODOs @@ -654,3 +654,4 @@ Changes from the initial implementation of simplified sliding sync. 4. Rename `unstable_expanded_timeline` to `expanded_timeline` 5. Add `lists` to room response 6. Add `membership` field to room response. +7. Change the format of `required_state` in the request.