0.2: stay logged in, soak test, installable web app, keepalive #88

Merged
littlefox merged 9 commits from issue-81-keepalive into main 2026-10-18 00:35:14 +00:00
Owner

Closes #53
Closes #66
Closes #81
Refs #51 (stays open until it's tried on real phones, which needs #71)

Four stacked branches in one PR to save CI time:

  • #53 Stay logged in: desktop "keep me logged in" stores the password only in the system keyring (keyring 3.6, pure-Rust Secret Service), logs in by itself next start, forgotten on logout; browser "remember me" keeps server+name only. Desktop CI image gains gnome-keyring + secret-tool (pushed); the smoke test checks store / auto-login / removal on logout.
  • #66 Soak: one minute in every e2e run (desktop), an hour nightly (soak.yml): posts + connection drops; exact unread count, same place, heap not doubled.
  • #51 Installable web app: manifest, icons, service worker (app shell only, opens offline), install button where the browser offers one, one-time iPhone hint.
  • #81 Keepalive: get-time every 45 s and on becoming visible; no answer in 20 s closes the connection (new Client::close) and reconnecting takes over.

Locally: 151 browser tests across the three profiles, desktop smoke test (incl. keyring) passes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XJW2ocwLunyaLiUwCBHEP8

Closes #53 Closes #66 Closes #81 Refs #51 (stays open until it's tried on real phones, which needs #71) Four stacked branches in one PR to save CI time: - #53 Stay logged in: desktop "keep me logged in" stores the password only in the system keyring (keyring 3.6, pure-Rust Secret Service), logs in by itself next start, forgotten on logout; browser "remember me" keeps server+name only. Desktop CI image gains gnome-keyring + secret-tool (pushed); the smoke test checks store / auto-login / removal on logout. - #66 Soak: one minute in every e2e run (desktop), an hour nightly (soak.yml): posts + connection drops; exact unread count, same place, heap not doubled. - #51 Installable web app: manifest, icons, service worker (app shell only, opens offline), install button where the browser offers one, one-time iPhone hint. - #81 Keepalive: get-time every 45 s and on becoming visible; no answer in 20 s closes the connection (new Client::close) and reconnecting takes over. Locally: 151 browser tests across the three profiles, desktop smoke test (incl. keyring) passes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01XJW2ocwLunyaLiUwCBHEP8
D-032: only where it's secure. The login page has a checkbox. On the
desktop with a working keyring it's "keep me logged in": the password
goes only into the system keyring (Secret Service, Keychain, Credential
Manager), the next start logs in by itself, and logging out deletes
it. Without a keyring, and in the browser, it's "remember me": the
server and name are pre-filled next time, the password never stored.

keyring 3.6 with its pure-Rust Secret Service backend (no new system
libraries for the packages); its calls run on their own threads, as it
blocks on its own runtime. The desktop CI image gains gnome-keyring
and secret-tool, and the smoke test checks storing, logging in by
itself after a restart, removal on logout, and no login after that.
remember.spec.ts checks the browser side, including that nothing in
storage looks like the password.

Refs #53

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJW2ocwLunyaLiUwCBHEP8
Reconnecting (#52) is only trustworthy if it holds up over time. In
soak.spec.ts Cecilia stays on post 57 while Anna posts to Allmänt, and
Cecilia's connection is cut every other post. Afterwards the unread
count must be exactly the number of posts, she must still be on post
57, every drop must have reconnected once, and the JS heap (exact, via
the DevTools protocol) must not have doubled. The normal e2e run does
one minute on desktop; a nightly workflow does an hour.

Locally: 30 s, 18 posts, 9 drops, heap 2.7 -> 3.0 MB.

Refs #66

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJW2ocwLunyaLiUwCBHEP8
D-031: the installable web app is the route to phones. The web build
now has a manifest, icons (rendered from the SVG with Chromium by
tools/render-icons.sh) and a service worker that caches the app itself,
so it starts fast and opens offline once loaded; LysKOM traffic never
goes through it. Where the browser offers to install (Android,
Chromium), settings has an "Installera NeoKOM som app" button. iPhones
and iPads have no install prompt, so their Safari gets a one-time hint
on the login page: tap Share, then Add to Home Screen.

pwa.spec.ts checks the manifest and icons, that the service worker
activates and the app opens offline (Chromium), and that the iPhone
hint shows once (WebKit) and never elsewhere. Trying it on real phones
needs HTTPS: #71.

Refs #51

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJW2ocwLunyaLiUwCBHEP8
A connection can hang silently (a laptop waking on another network, a
NAT forgetting the flow): nothing arrives and calls wait forever, so
reconnecting (#52) never started. The main view now asks the server
the time every 45 s and when the page becomes visible again; no answer
within 20 s closes the connection with the new Client::close(), and
reconnecting takes over as for any drop.

A unit test closes a hung in-memory connection; reconnect.spec.ts makes
the app's socket pass nothing (open but dead) and checks that NeoKOM
reconnects and returns to the same post.

Refs #81

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJW2ocwLunyaLiUwCBHEP8
Merge remote-tracking branch 'origin/main' into issue-81-keepalive
Some checks failed
packaging / debian (pull_request) Has started running
packaging / fedora (pull_request) Has started running
packaging / nix (pull_request) Has started running
ci / e2e (push) Has started running
ci / check (push) Successful in 9m15s
packaging / arch (pull_request) Successful in 14m9s
packaging / release (pull_request) Has been cancelled
ci / desktop (push) Failing after 25m0s
fe20c4ce05
Clippy: let chains after the rust-version 1.88 bump
Some checks failed
packaging / fedora (pull_request) Has started running
packaging / nix (pull_request) Has started running
ci / check (push) Successful in 9m54s
packaging / arch (pull_request) Successful in 13m16s
ci / desktop (push) Successful in 13m56s
ci / e2e (push) Failing after 28m3s
packaging / debian (pull_request) Successful in 30m7s
packaging / release (pull_request) Has been cancelled
55d7c6d6ec
The relay (#85) merged before rust-version went to 1.88 (#83), so main
fails clippy there; this also covers the login code in this branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJW2ocwLunyaLiUwCBHEP8
soak: on a count mismatch, report a fresh login's count too
All checks were successful
ci / check (push) Successful in 9m27s
packaging / arch (pull_request) Successful in 12m57s
ci / desktop (push) Successful in 13m0s
packaging / nix (pull_request) Successful in 18m36s
ci / e2e (push) Successful in 21m34s
packaging / debian (pull_request) Successful in 22m34s
packaging / fedora (pull_request) Successful in 26m59s
packaging / release (pull_request) Has been skipped
75813822cb
CI run #150 ended 2 short in Allmänt (both attempts), which doesn't
reproduce locally. The failure message now has the starting count,
posts, drops, the app's count and a fresh login's count, to tell a
counting bug from a test bug.

Refs #66

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJW2ocwLunyaLiUwCBHEP8
littlefox referenced this pull request from a commit 2026-10-18 14:33:48 +00:00
Sign in to join this conversation.
No description provided.