The service worker answers app routes from its kept page (#395), and it
kept whatever the mount's root returned at install and whatever HTML a
navigation returned. Where the root is not the app -- demo.ihasmail.com
puts its landing page there -- a returning visitor got the landing page on
every route.
The kept page is now only ever the app page, recognised by the asset list
the build writes into it: install fetches /mail instead of /, a
navigation's page is kept only if it is the app's, and a foreign page left
by the earlier worker is dropped when this one activates. Only the app's
own routes are answered from it; the root and any page in front of the app
go to the network. The reload for a new build primes the kept page from
/mail for the same reason.
* Start at once on a device marked as your own
On a distant link, opening the app waited on four round trips before the
inbox showed: the app page, the session, the folder list, then the folder.
A trusted device now starts from what it kept:
- the service worker answers an app route from its kept page and fetches a
fresh one behind it; the app checks the server's version at start, and a
reload for a new build puts the new page in place first, so it is not
answered with the old one. Assets of the page just replaced are kept one
build longer for a tab still running it.
- the session's public details, so requests for mail go out before the
server has confirmed the session; the answer replaces it, and a session
that has ended lands on the sign-in form as before.
- the folder list and the first page of up to four recently read folders,
list properties only, so the folders and the inbox paint before any reply
and the folder query does not wait on the folder list. The "folder no
longer exists" check still waits for the server's list.
All of it goes through the storage gate: nothing is written or read on a
device not marked as the reader's own, and signing out clears it.
* Show nothing kept before the session is confirmed
Starting from a kept session put the kept inbox on screen before the
server had said the session was still good; a session that had ended
showed mail and then the sign-in form. The spinner stays until the
server answers, as before.
The kept session is gone -- it existed only to start early. The kept
folder list and rows are still applied, from setAccount, which runs once
the session is confirmed: the inbox paints the moment that answer
arrives, and the folder query goes out then without waiting on the
folder list. An unreachable server lands on the sign-in form as before.
The app page names only what it loads at start. The composer, settings,
viewers and the rest were fetched when first used, and after every deploy
that first use waited on the server -- and the worker's tidy-up dropped
them again at the next deploy anyway.
The build now writes the list of all its files into the page as an inert
JSON block. The service worker keeps everything listed and, once a page
names files it does not hold, fetches them three at a time; a load cut
short is resumed at the next navigation. Language catalogs are listed
apart and left to be cached when used, and nothing is fetched ahead when
the browser is set to save data.
A pushed mail change took three round trips: Email/changes beside a
Mailbox/get, then Email/get for what changed, then the list, the open
thread and a second Mailbox/get. Each page of changes now carries its own
Email/get calls by back-reference, and the one Mailbox/get goes out with
it, so a push settles in two. New mail fetched this way is not asked for
again by the notice.
A reply's sessionState that differs from the session is announced once
rather than on every reply, and session refreshes in flight are shared.
The mock's session state now matches the sessionState on its replies, as
Stalwart's does; tying it to the data counter made every reply trigger a
session refresh in development.
On a 250 ms link, opening a conversation took two round trips: Thread/get,
then the bodies. It now takes one. A known thread sends Thread/get and the
missing bodies in the same tick; an unknown one chains Email/get off
Thread/get with a back-reference, and falls back to fetching in parts when
the thread is longer than one Email/get may carry.
Conversations also start loading before the click: when the pointer rests
on a row, as soon as a press begins, and for the row below the open one.
The open waits for that load and does not repeat it.
Going back to one of the last twelve folders shows its previous list at
once, less messages that have left it, while the query runs.