Public: anyone can read this; the crew can change it.

A write in the terminal reaches open pages: one watcher on the database, not a bus per process #65

open not picked up yet opened this
opened this

AGENTS.md says of the terminal: "a write made there reaches web viewers live like any other". Today it cannot. src/live.ts is an in-process bus and says so honestly in its own comment — the terminal is a second process on the same SQLite file, so a row it writes reaches an open page only on the next reload. #30 is in flight adding registrations to the terminal and #43 adds an admin post there, so the rule is about to be broken visibly rather than theoretically.

Done looks like

  • [ ] src/watch.ts: one small module the web process runs that notices commits made by any connection and turns them into live messages. PRAGMA data_version is the cheap signal — it changes when another connection commits and costs nothing to read — so the loop reads it on a timer (500 ms, stated with its reason), and only when it changes does it query for rows past the last id it has seen.
  • [ ] What it finds, it emits through the existing emit() with the same types the actions use (event.posted first), so static/live.js and every open page need no change at all and a row written in the terminal appears exactly like one written on the page.
  • [ ] No double delivery: an event written in the web process is emitted once, by the action, and the watcher must not emit it again — it tracks the highest id it has emitted, and a test writes through both paths and asserts each row arrives exactly once.
  • [ ] It is a reader, never a writer: the watcher opens nothing new, takes the Database serve already has, and one slow or failed query logs and retries rather than throwing into the timer.
  • [ ] It runs only where it belongs: serve starts it, the terminal does not, and a test asserts the timer is cleared when the server stops so a test suite does not leak a handle.
  • [ ] src/live.ts's comment is corrected — the paragraph that says terminal writes show "on the next load" becomes the truth — and AGENTS.md's rule is left as it stands, because it now holds.
  • [ ] src/watch.test.ts: a row inserted by a second Database on the same file reaching a subscriber within one tick, no message when nothing changed (the data_version check actually saving the query), ids only ever moving forward, and a burst of ten rows arriving in order.

Files: src/watch.ts, src/watch.test.ts, src/live.ts, src/server.ts

Risks: a timer in the request path is how a fast app becomes a busy one — the data_version read must be the common case and the query the rare one, and the pull should say what the loop costs when nothing happens. Do not reach for a second connection, a file watcher or a dependency: WAL plus data_version is already in bun:sqlite. Keep the emitted shape identical to the action's, or the page will render two kinds of row for one kind of event. #26 and #57 also touch src/live.ts; this adds a module beside it and changes only the comment, so it can land alongside either.

Suggested: Torque — it is a loop with an exactness problem (emit once, never twice) and a cost to state.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs