Every connected client sent a Core/echo every 30 seconds for as long as
the page was open, background tabs included: 120 requests an hour per
login, which on an otherwise idle night made up nearly all the traffic
a server saw. A client with an SSE stream already hears from the server
every 30 seconds, since the stream is opened with ping=30.
The keep-alive tick now skips the echo when the stream delivered an
event or a ping within the last 45 seconds and the previous echo did not
fail. A stream that goes quiet or drops lets the echo through again on
the next tick, so a lost connection is still reported and reconnected
as before, at most one tick later. Clients without a stream (no
eventSourceUrl, or over the per-tab stream budget) keep pinging every
30 seconds.
getTagCounts sends two Email/query per tag: 240 method calls for 120
tags, and the sidebar re-runs it after every push. A server that
advertises the keywords capability with supportsCounts already reports
each keyword's total and unread in Keyword/get, so the counts now come
from one call there, and from the queries as before everywhere else or
when that call fails.
Trash and Junk (#1156) are not subtracted on this path. Keyword/get has
no filter, and taking them out would need the two per-tag queries this
avoids. The counts are the server's own for the keyword; a gateway that
maps tags to provider labels reports what the provider shows for the
label.
Stalwart's x:ArchivedItem/query without calculateTotal scans ids
ascending, stops at 5000 and only then reverses them, so the newest
items of a large archive never showed, and admin accounts got every
account's items. The review of the branch also found gaps around
account switches, restores and focus.
- Read the archive in pages of 500 with calculateTotal, newest first,
stop at a whole page older than the days limit, and offer
"Show older" after 2000 items; detection asks for one item.
- Send the accountId filter and fall back without it on
unsupportedFilter; keep only items of the account, never one without
an account id.
- Ask nothing until config and policy are loaded and the policy is the
current account's; the later check after a refusal is forced.
- Show the Trash link only when the archive holds a message inside the
days limit; the Settings page shows whenever the server has the
feature and says that archiving must be on in Stalwart.
- Restore: notFound leaves the list with a note, forbidden hides the
page, results for another account are dropped, the button keeps focus.
- Forget what servers said at a full sign-out.
The first version wrote the whole tag list on every change, guessed a
group when the server wouldn't say, and treated a failed read like a
server without metadata. Now:
- Definitions are a map by tag id under `tags`, and each change patches
one tag (`metadata/org.bulwarkmail.tags/tags/<id>`), so two members
adding tags at once both keep theirs. Fields and colors this version
doesn't know survive. The `{ list }` and bare-array shapes are still
read and converted by the first save.
- Shared tags appear only for confirmed group principals. A failed
principal lookup keeps the user's own tags and asks again later.
- "No metadata advertised" (0.16) and "the read failed" are separate.
A failed read keeps the last good tags; a failed save keeps the change,
says so, and sends it with the next good read after the client's
pause.
- Push reloads wait for 5 s of quiet and skip the echo of our own save;
a returning tab reloads definitions only, and the scan for unnamed tags
runs once per sign-in and then at most every 30 minutes.
- The editor names its buttons after the tag, shows the delete warning
and 44 px buttons on phones, returns focus to the edit button, and
asks for Inbox rights only for confirmed groups.
- `directory:read` for api.user.findPeople, with at least 3 characters,
at most 20 ids, 20 results and 10 lookups a minute, in the directory
of the account the call names; one load in flight per client.
- Plugins hear `group` only for accounts the server confirmed are group
principals; the policy's fallback stays for the admin's scopes.
- The email.* keyword methods refuse $draft, $junk, $notjunk and
$phishing.
- A plugin keeps at most 4 KB in a mailbox and reads it 30 times a
minute; the email:write consent text says others in a team mailbox
can read it.
- email.updateKeywords also changes the rows of expanded conversations.