feat(host): a shared follower for reads over Neon Realtime, used by nothing yet

Merged
CH
6d ago
+362-0

This PR changes no user-visible behaviour, because nothing uses the new module yet. It's the third of three Realtime plumbing PRs split out of #3232, stacked on the PR that seals through drizzleAdapter(). Every Realtime PR is on hold, so please don't merge it yet.

What it does

packages/host/src/live-follow.ts follows a read the service sealed, the way Neon's guide describes:

  • liveRows subscribes to every part's sealed statement on one socket. Once every part has its first result, it emits all the parts' rows together on each change, undecoded, for the caller to decode.
  • Renewal: every seal is renewed ten seconds before the earliest one expires. A reseal that fails is retried a second later.
  • Failure: the stream fails with LiveBroken if Realtime's client doesn't load, a subscription stops for good, or a renewal is refused.
  • openRealtimeClient loads Realtime's own client the first time a read is followed, so it stays out of the web app's first load.

Dependency: this PR adds @neon/realtime back to @luke/host, which #4074 removed along with the account inbox's follower.

live-follow.test.ts drives it with a scripted Realtime and TestClock.

For reviewers: this is #3232's generic follower as it was. It doesn't include the diagnostics main later added to the account inbox's own follower, which are the first-answer watchdog, restarting on return, and the Realtime trouble report (#4062, #4064, #4067). After #4074 there's no account inbox follower on main.

Stack

  1. #4071, the immutability test helper (base main)
  2. Seal through drizzleAdapter() (base: PR 1)
  3. This PR
  4. #3232, the plan and agent scope inbox (base: this PR)