From 094ccd7d81ab25c9e59abd5fdfe4cceedd4fd7f5 Mon Sep 17 00:00:00 2001 From: Brian Krabach Date: Sat, 4 Apr 2026 07:06:53 -0700 Subject: [PATCH] feat: fire bell-clear POST when opening remote sessions --- muxplex/frontend/app.js | 5 ++++ muxplex/tests/test_frontend_js.py | 44 +++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/muxplex/frontend/app.js b/muxplex/frontend/app.js index f5b3a0a..a5ca450 100644 --- a/muxplex/frontend/app.js +++ b/muxplex/frontend/app.js @@ -1236,6 +1236,11 @@ async function openSession(name, opts = {}) { return closeSession(); } + // Fire-and-forget bell-clear for remote sessions — acknowledge bells on the remote server + if (_remoteId !== '') { + api('POST', '/api/federation/' + encodeURIComponent(_remoteId) + '/sessions/' + encodeURIComponent(name) + '/bell/clear').catch(function() {}); + } + // Wait for animation to finish (may already be done if /connect was slow) await animDone; diff --git a/muxplex/tests/test_frontend_js.py b/muxplex/tests/test_frontend_js.py index e937725..5cdee75 100644 --- a/muxplex/tests/test_frontend_js.py +++ b/muxplex/tests/test_frontend_js.py @@ -2543,3 +2543,47 @@ def test_update_session_pill_uses_session_key_or_name() -> None: assert "sessionKey" in body, ( "updateSessionPill must compare using s.sessionKey || s.name (not just s.name)" ) + + +# ─── task-5-open-session-bell-clear ───────────────────────────────────────── + + +def test_open_session_fires_bell_clear_for_remote() -> None: + """openSession must fire a bell/clear POST to the federation proxy for remote sessions.""" + match = re.search( + r"async function openSession\s*\(.*?\)\s*\{(.*?)^\}", + _JS, + re.DOTALL | re.MULTILINE, + ) + assert match, "openSession function not found" + body = match.group(1) + # Must POST to federation bell/clear endpoint when _remoteId is not empty + assert "/bell/clear" in body, ( + "openSession must POST to /api/federation/{remoteId}/sessions/{name}/bell/clear" + ) + # Must guard bell-clear with a _remoteId !== '' check + assert "_remoteId !== ''" in body, ( + "openSession must guard bell-clear POST with _remoteId !== '' check" + ) + + +def test_open_session_bell_clear_is_fire_and_forget() -> None: + """openSession bell-clear POST must be fire-and-forget using .catch() to swallow errors.""" + match = re.search( + r"async function openSession\s*\(.*?\)\s*\{(.*?)^\}", + _JS, + re.DOTALL | re.MULTILINE, + ) + assert match, "openSession function not found" + body = match.group(1) + # Must use .catch(function() {}) to swallow errors — not awaited + assert ".catch(function() {})" in body, ( + "openSession bell-clear POST must swallow errors with .catch(function() {})" + ) + # Must NOT await the bell-clear call (it's fire-and-forget) + bell_clear_lines = [line for line in body.splitlines() if "/bell/clear" in line] + assert bell_clear_lines, "openSession must contain a bell/clear call" + for line in bell_clear_lines: + assert "await" not in line, ( + f"openSession bell-clear POST must NOT be awaited (fire-and-forget): {line.strip()}" + )