Web client (warp-web) with E2EE, and two sync fixes
CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Test (windows-latest) (push) Canceled after 0s
CI / Storage tests on PostgreSQL (push) Canceled after 0s
CI / Complement (federation off) (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
CI / Smoke test the binary (push) Canceled after 0s
CI / Admin panel (push) Canceled after 0s
CI / Web client (push) Canceled after 0s
CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Test (windows-latest) (push) Canceled after 0s
CI / Storage tests on PostgreSQL (push) Canceled after 0s
CI / Complement (federation off) (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
CI / Smoke test the binary (push) Canceled after 0s
CI / Admin panel (push) Canceled after 0s
CI / Web client (push) Canceled after 0s
apps/web: a Matrix client for the browser on Vue 3, Tailwind and matrix-js-sdk, built on @warp/ui. Like the admin panel it is an optional, separate service: warp-web embeds the built app, serves /config.json and proxies only /_matrix/client and /_matrix/media to the homeserver (or, with -public-homeserver, lets the browser call it directly). Sign-in and sign-up with registration tokens, room list, timeline with back-pagination, text, images, video and files over authenticated media, local echo with sent/read/failed states, receipts, typing, invites, creating, joining and leaving rooms, room info, settings, phone layout. End-to-end encryption through the Rust crypto: encrypted messages and files, emoji verification, key backup setup and restore. apps/ui: WRoomItem, WMessageBubble and WComposer from the brand package, and the icons the client needs. syncapi fixes found with the client: - A room joined inside the sync window was sent as the join alone with limited: false, so clients thought they had the whole room. It is now read like an initial sync; a profile change is not mistaken for a join. - A live typing notification was reported on every sync, so every long poll returned at once while anybody typed. Typing now has a position in the sync token and is reported when it changes, including the empty list when the last person stops. Also: Dockerfile, a `web` compose profile, Makefile targets, a CI job with a proxy smoke test, docs. PLAN.md moves out of the repository. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
adc18e7cf3
commit
b6f3be6ac4
90 files changed
+6608
-472
No files matched your search
+33
-7
@@ -42,7 +42,7 @@ second place for them to disagree.
|
||||
|
||||
## Stream tokens
|
||||
|
||||
A sync response is assembled from seven streams that move independently:
|
||||
A sync response is assembled from eight streams that move independently:
|
||||
|
||||
| Stream | Moves when | Position from |
|
||||
|---|---|---|
|
||||
@@ -53,18 +53,19 @@ A sync response is assembled from seven streams that move independently:
|
||||
| presence | somebody's presence actually changes | `sync_sequences` |
|
||||
| device list | somebody's end-to-end keys change ([e2ee.md](e2ee.md)) | `keyserver_sequences` |
|
||||
| notification | a user's unread counts in a room move ([push.md](push.md)) | `push_sequences` |
|
||||
| typing | somebody starts or stops typing, or a notification runs out | a counter in memory (see [Typing](#typing)) |
|
||||
|
||||
A client that has seen receipt 7 but only event 4 has to be able to say so
|
||||
in the one opaque string the API gives it, so a token names a position in
|
||||
each:
|
||||
|
||||
```
|
||||
s{pdu}_{receipt}_{to_device}_{account_data}_{presence}_{device_list}_{notification}
|
||||
s{pdu}_{receipt}_{to_device}_{account_data}_{presence}_{device_list}_{notification}_{typing}
|
||||
```
|
||||
|
||||
Trailing zeroes are left off, so a client that has only ever seen room
|
||||
events carries `s12` rather than `s12_0_0_0_0_0_0`. The device list and
|
||||
notification positions came later (Phases 7 and 8) and were added at the
|
||||
events carries `s12` rather than `s12_0_0_0_0_0_0_0`. The device list,
|
||||
notification and typing positions came later and were added at the
|
||||
end. A token with fewer
|
||||
positions than this build writes is accepted and the missing ones read as
|
||||
zero — which is what lets a token stored before a stream existed go on
|
||||
@@ -167,6 +168,21 @@ cases, which `roomserver.syncState` implements:
|
||||
A timeline that reaches back to the room's create event reports no state at
|
||||
all: there is nothing before it.
|
||||
|
||||
### A room joined inside the window
|
||||
|
||||
To the client, a room the user has just joined is new: it has none of its
|
||||
history and none of its state. So an incremental sync reads such a room
|
||||
the way an initial sync does — the recent history the user may see and the
|
||||
whole state before it — instead of the events since `since`, which would
|
||||
be the join alone with `limited: false`, telling the client it has
|
||||
everything.
|
||||
|
||||
"Joined inside the window" means the user's latest membership event is in
|
||||
the window *and* the membership before it was not already `join`. A
|
||||
display name or avatar change is a new join event too, but resending the
|
||||
room's history for one would be wrong; `roomserver.MembershipBefore` tells
|
||||
the two apart.
|
||||
|
||||
## Visibility
|
||||
|
||||
`roomserver.VisibleRange` answers "what span of this room may this user
|
||||
@@ -331,9 +347,19 @@ having stopped typing, and a second process would not see them. The second
|
||||
only matters when Warp stops being one process, which PLAN.md says is not
|
||||
the plan.
|
||||
|
||||
They therefore have no stream position. A notification that started and
|
||||
stopped between two syncs is simply never reported; one that is live is
|
||||
reported on every sync until it expires.
|
||||
Their stream position is a counter in the tracker that moves on every
|
||||
change, with each room remembering the position of its last one. A sync
|
||||
reports a room's typing list when it changed inside the window — including
|
||||
to empty, which is how a client hears that somebody stopped — and not
|
||||
again while it stays the same. Reporting a live notification on every sync
|
||||
instead would make every long poll return at once while anybody typed: a
|
||||
busy loop that ends in the rate limiter.
|
||||
|
||||
The counter starts at zero again after a restart, so a client's typing
|
||||
position is compared for difference, never for order: one the tracker has
|
||||
never reached is from before the restart, and every room it knows of
|
||||
counts as changed. A notification that started and stopped between two
|
||||
syncs is reported as the empty list, which is what the client already had.
|
||||
|
||||
### Receipts
|
||||
|
||||
|
||||
Reference in new issue
Block a user