Merge main into wave/a-grid-frame
Two conflicts, both expected.
**`invalidate_relabelled` (improvise-hkt6, WU-K).** Both sides kept: the
signature and the item-tuple comparison are this branch's — `old` is an
`AxisFrame` now, and a group header appearing or collapsing must not blank
cells it did not rename — and the totals blanking and its whole argument are
main's. `grid_updates` still diffs the totals against the *framed* mirror,
which is what makes a renamed column whose total did not change send one;
`a_relabelled_column_drops_its_total`,
`a_relabelled_row_leaves_the_totals_alone` and
`a_renamed_column_whose_total_did_not_change_still_gets_its_total_back` all
pass against the new frame.
**`lib.rs`'s composition test.** Main's deletion taken: 18189c1 moved
`client_showing`, `published_basis` and
`a_client_composes_a_write_from_the_id_it_was_given` into `socket.rs` when
it consolidated `set_cell_at` and `typed`.
Main's new `GridUpdate::RowLabels`/`ColLabels` call sites are converted, and
five doc comments naming the retired spellings with them — a fact stated in
several places is a grep, not an edit.
1327 passing, 0 failing. clippy/fmt clean, wasm gate clean, both bundles
build.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+32
-3
@@ -39,6 +39,9 @@
|
||||
// Neither is reachable silently. Every transport writes what it is doing to
|
||||
// `#status` — "starting", "connected", "cannot reach …", "disconnected" — so
|
||||
// a peer that never arrives reads differently from one that went away.
|
||||
// "disconnected" means exactly the second: a socket that opened and then
|
||||
// closed. A socket that never opened keeps saying "cannot reach …", because
|
||||
// the close event there is the tail of the failure and not news.
|
||||
|
||||
import init, { Client } from "./pkg/improvise_wasm_client.js";
|
||||
|
||||
@@ -206,8 +209,17 @@ function workerTransport() {
|
||||
/** A websocket to `improvise-ws-server`: how a TUI-hosted document is shared. */
|
||||
function socketTransport() {
|
||||
const socket = new WebSocket(WS_URL);
|
||||
const unreachable = `cannot reach ${WS_URL} — is improvise-ws-server running?`;
|
||||
// Did this socket ever open? The page has to record that itself, because
|
||||
// nothing on the close event carries it: `readyState` is already CLOSED by
|
||||
// the time a close listener runs, whichever happened, and a refused
|
||||
// connection and a mid-session network drop are BOTH code 1006 with
|
||||
// `wasClean: false`. So "never connected" and "was connected and went away"
|
||||
// are distinguishable only by remembering.
|
||||
let opened = false;
|
||||
const ready = new Promise((resolve) => {
|
||||
socket.addEventListener("open", () => {
|
||||
opened = true;
|
||||
setShellStatus(`connected · ${WS_URL}`);
|
||||
resolve();
|
||||
});
|
||||
@@ -215,10 +227,27 @@ function socketTransport() {
|
||||
socket.addEventListener("message", (event) => onFrame(event.data));
|
||||
// Without this, a connection that never opens left #status blank and
|
||||
// "server not running" read exactly like "still connecting" (improvise-hwpi).
|
||||
socket.addEventListener("error", () =>
|
||||
setShellFailure(`cannot reach ${WS_URL} — is improvise-ws-server running?`),
|
||||
socket.addEventListener("error", () => setShellFailure(unreachable));
|
||||
// A socket that never opened did not "disconnect" — it failed to connect,
|
||||
// and the close event is the tail of that failure rather than a second,
|
||||
// vaguer thing that happened (improvise-taxx). Writing "disconnected" here
|
||||
// unconditionally replaced the `error` listener's precise message with the
|
||||
// least informative of the two facts.
|
||||
//
|
||||
// Same family as the watchdog bug and NOT the same fix: the watchdog is
|
||||
// disarmed because it is for silence only, whereas suppressing `close`
|
||||
// outright would hide a genuine mid-session disconnect, which is the one
|
||||
// thing this listener is really for. Hence the split rather than a guard.
|
||||
// Both arms go through `setShellFailure`, which DISARMS the watchdog. That
|
||||
// matters on the opened path: the watchdog is armed after `transport.ready`
|
||||
// resolves — i.e. on `open` — so a socket that opened and then dropped
|
||||
// before its first frame reaches here with the timer still pending, and
|
||||
// "disconnected" is more precise than the guess it would otherwise fire 8s
|
||||
// later. On the never-opened path there is no timer yet and the clear is a
|
||||
// no-op. Neither arm leaves one armed.
|
||||
socket.addEventListener("close", () =>
|
||||
setShellFailure(opened ? "disconnected" : unreachable),
|
||||
);
|
||||
socket.addEventListener("close", () => setShellStatus("disconnected"));
|
||||
setShellStatus(`connecting to ${WS_URL}…`);
|
||||
return {
|
||||
send: (text) => {
|
||||
|
||||
Reference in New Issue
Block a user