fix(web): default the socket to TLS, and cache-bust the deployed bundles

?ws= now takes a host:port and the page supplies the scheme: wss:// when it
is itself served over https, ws:// when over http. An explicit ws:// from an
https page is UPGRADED rather than passed through, because an https origin
refuses it as mixed content -- so passing it through can only produce a
failure that reads like 'the server is not running'. The scheme is not the
caller's to get wrong.

And the deploy now stamps ?v=<sha> onto both bundles. Pages serves everything
max-age=600 and the wasm-pack filenames carry no content hash, so for ten
minutes after a deploy a returning visitor runs the PREVIOUS build -- which
made a shipped fix look like it had not shipped, twice, during the first real
browser debugging session.

BOTH halves are stamped, because a fresh glue file does not pull a fresh
.wasm: the glue locates it with new URL('..._bg.wasm', import.meta.url), and
a URL built against a base does not inherit the base's query. Stamping only
the import specifier would refresh the wrapper and keep the stale binary --
exactly the failure this is here to end.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EoW5BB87ZZdm96SvBTWawH
This commit is contained in:
Edward Langley
2026-09-19 21:17:08 -07:00
parent 6e1ba77d70
commit 94d26d8705
4 changed files with 76 additions and 18 deletions
+12 -6
View File
@@ -207,13 +207,19 @@ document open in the TUI is shared — start the websocket server and pass
cargo run -p improvise-ws-server -- examples/demo.improv --port 8787
```
then reload with `?ws=ws://127.0.0.1:8787`.
then reload with `?ws=127.0.0.1:8787`.
**That form works only from a page served over `http://localhost`.** From the
deployed https page the address must be `wss://`, because a `ws://` one is
blocked as mixed content — and `improvise-ws-server` speaks plain `ws://`
only, so reaching it from https means terminating TLS in front of it (a
reverse proxy or a tunnel). Native `wss://` is not implemented.
**The scheme is not yours to supply and defaults to TLS.** `?ws=` takes a
`host:port`; the page uses `wss://` when it is itself served over https and
`ws://` when it is served over http, because an https origin refuses a `ws://`
address as mixed content. An explicit `ws://` from an https page is upgraded
rather than passed through — passing it through can only produce a failure
that reads like "the server is not running".
So the local pairing above works as written. Reaching a server from the
**deployed** https page means terminating TLS in front of it (a reverse proxy
or a tunnel): `improvise-ws-server` speaks plain `ws://` only, and native
`wss://` is not implemented.
Caveat worth stating plainly: **no line of the browser JavaScript has ever
run.** There is no browser and no headless DOM in the development environment,