feat: incremental (delta) sync for mailbox refresh#7
Open
Aravinda-HWK wants to merge 1 commit into
Open
Conversation
Implements Phase 3 of the Email 2.0 proposal: refresh now fetches only
what changed instead of re-listing the whole folder.
Because go-imap v1 exposes no CONDSTORE/MODSEQ, the delta is computed from
UIDs + flags rather than a MODSEQ token:
Server
- New GET /api/v1/mailboxes/{mailbox}/changes endpoint returning a
MailboxDelta {uidvalidity, total, resync, added, flags, removed}.
- imap.MailboxChanges: UID SEARCH (since+1):* for new envelopes, a
flags-only UID FETCH over the client's known UIDs to derive flag
changes + removals; UIDVALIDITY mismatch signals a full resync.
- ListMessages now also returns uidvalidity so the client has a baseline.
- Factored shared fetchEnvelopes/fetchFlags helpers.
Client
- Dexie v2 syncMeta table persists uidvalidity per folder.
- mailboxes.changes() endpoint + MailboxDelta/FlagUpdate types.
- DataContext reconciles added/removed/flag changes idempotently (keyed
on UID) and exposes refreshFolder(role); a ThreadList refresh button
wires it into Inbox/Sent/Trash.
Performance
- refreshFolder syncs only the viewed folder, so four folder syncs no
longer serialize on the session's single IMAP connection.
- IMAPFor drops a redundant per-request NOOP probe (one RTT) since every
operation already self-heals via ensureLive.
Tests: parseUIDList unit tests; server build + go test and frontend
typecheck pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Implements Phase 3 (delta sync) of the Email 2.0 proposal: refreshing a mailbox now fetches only what changed instead of re-listing the whole folder.
Because
go-imapv1 exposes no CONDSTORE/MODSEQ, the delta is computed from UIDs + flags rather than a MODSEQ token (the proposal's documented fallback in §10).How it works
The client sends the UIDs it already holds + its cached
UIDVALIDITY; the server returns only:UID SEARCH (since+1):*)UIDVALIDITYchanged, telling the client to discard its cache and refetchChanges
Server
GET /api/v1/mailboxes/{mailbox}/changes→MailboxDeltaimap.MailboxChanges+ sharedfetchEnvelopes/fetchFlagshelpersListMessagesnow also returnsuidvalidity(baseline for the client)Client
syncMetatable persistsuidvalidityper foldermailboxes.changes()endpoint +MailboxDelta/FlagUpdatetypesDataContextreconciles added/removed/flag changes idempotently (keyed on UID); newrefreshFolder(role)and a ThreadList refresh button wired into Inbox/Sent/TrashPerformance
refreshFoldersyncs only the viewed folder, so four folder syncs no longer serialize on the session's single IMAP connectionIMAPFordrops a redundant per-requestNOOPprobe (one RTT) — every operation already self-heals viaensureLiveTogether these cut a refresh from ~4.25s (four folders contending on one connection) to a single sub-second
changesrequest.Tests
parseUIDListunit tests addedgo build ./...,go test ./..., and frontendtsc --noEmitall passNotes / follow-ups