Start at once on a device marked as your own #395

Closed
opened 2026-09-16 20:38:28 +00:00 by jcoffey-dev · 0 comments
Owner

The last of the high-latency items. Before this change, on a 250 ms link the inbox showed only after about four round trips: the app page, then the session, then the folder list, then the folder.

Rule kept throughout: nothing kept is shown before the server confirms the session. Until then the app shows the spinner, and a session that has ended goes from the spinner to the sign-in form. (An earlier revision of this PR started from a kept session and painted the kept inbox first; that was removed.)

What changes:

  1. App page from the service worker.
    • An app route is answered from the kept page immediately, so the spinner no longer waits a round trip for the HTML. A fresh copy is fetched behind it.
    • Addresses that end in a file name still go to the network, as does a first visit with no kept copy.
    • A kept page may be a build behind:
      • The app now checks /api/health at start whenever a worker controls the page.
      • A reload for a new build first puts the new page into the cache, so the reload isn't answered with the old page again. The existing once-per-version guard still prevents loops.
      • When the page changes, the replaced page's assets are kept for one more build, so a tab still running it can load its chunks.
  2. Kept folder list and list rows, on trusted devices only.
    • Stored: the folder list, plus the first page (up to 50 rows) of up to 4 recently read folders, with list properties only and no bodies. The total is capped at 400 KB, and saves are debounced by 3 s and flushed on pagehide.
    • It goes through the existing storage gate: nothing is written or read unless "This is my own device" was ticked, and signing out clears it. A snapshot belongs to one account.
    • It's applied from setAccount, which runs only once the session is confirmed. At that moment the folders and rows paint (mailboxesCached), and the folder query goes out without waiting for the server's folder list.
    • The "folder no longer exists" redirect still waits for the server's list, so a folder created on another device isn't mistaken for a deleted one.

Measured behind the latency proxy (3 s per round trip):

  • The page loaded from the worker, and the spinner showed with no rows until the session answer at about 3.2 s.
  • 29 rows appeared at that moment, one round trip before the list query could answer.
  • No session was stored.

Docs. FEATURES.md is updated in two places: the "Kept on the computer" row and the PWA navigation description. It also says plainly that nothing kept is shown before the session is confirmed.

Tests. Web: 1,371 pass, with 8 new cases:

  • the snapshot has no bodies, and isn't built before the server's folder list arrives;
  • restore paints folders and rows;
  • nothing is written or read on an untrusted device;
  • a sign-out beats a pending save;
  • a snapshot belongs to one account;
  • nothing kept is applied while the session is unconfirmed, and it arrives with the answer;
  • no session is stored.

Typecheck is clean.

No new UI strings.

Merged 2026-09-16 as coffey-labs/ihasmail@82dc877fe1

Rebuilt from: GH Archive, git history, session transcript.

The last of the high-latency items. Before this change, on a 250 ms link the inbox showed only after about four round trips: the app page, then the session, then the folder list, then the folder. **Rule kept throughout:** nothing kept is shown before the server confirms the session. Until then the app shows the spinner, and a session that has ended goes from the spinner to the sign-in form. (An earlier revision of this PR started from a kept session and painted the kept inbox first; that was removed.) **What changes:** 1. **App page from the service worker.** - An app route is answered from the kept page immediately, so the spinner no longer waits a round trip for the HTML. A fresh copy is fetched behind it. - Addresses that end in a file name still go to the network, as does a first visit with no kept copy. - A kept page may be a build behind: - The app now checks `/api/health` at start whenever a worker controls the page. - A reload for a new build first puts the new page into the cache, so the reload isn't answered with the old page again. The existing once-per-version guard still prevents loops. - When the page changes, the replaced page's assets are kept for one more build, so a tab still running it can load its chunks. 2. **Kept folder list and list rows, on trusted devices only.** - Stored: the folder list, plus the first page (up to 50 rows) of up to 4 recently read folders, with list properties only and no bodies. The total is capped at 400 KB, and saves are debounced by 3 s and flushed on `pagehide`. - It goes through the existing storage gate: nothing is written or read unless "This is my own device" was ticked, and signing out clears it. A snapshot belongs to one account. - It's applied from `setAccount`, which runs only once the session is confirmed. At that moment the folders and rows paint (`mailboxesCached`), and the folder query goes out without waiting for the server's folder list. - The "folder no longer exists" redirect still waits for the server's list, so a folder created on another device isn't mistaken for a deleted one. **Measured behind the latency proxy (3 s per round trip):** - The page loaded from the worker, and the spinner showed with no rows until the session answer at about 3.2 s. - 29 rows appeared at that moment, one round trip before the list query could answer. - No session was stored. **Docs.** FEATURES.md is updated in two places: the "Kept on the computer" row and the PWA navigation description. It also says plainly that nothing kept is shown before the session is confirmed. **Tests.** Web: 1,371 pass, with 8 new cases: - the snapshot has no bodies, and isn't built before the server's folder list arrives; - restore paints folders and rows; - nothing is written or read on an untrusted device; - a sign-out beats a pending save; - a snapshot belongs to one account; - nothing kept is applied while the session is unconfirmed, and it arrives with the answer; - no session is stored. Typecheck is clean. No new UI strings. **Merged** 2026-09-16 as coffey-labs/ihasmail@82dc877fe19b <sub>Rebuilt from: GH Archive, git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.