feat(host): a shared follower for reads over Neon Realtime, used by nothing yet
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:
liveRowssubscribes 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
LiveBrokenif Realtime's client doesn't load, a subscription stops for good, or a renewal is refused. openRealtimeClientloads 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.