From 1602528e474cb3b1fc9f90fde3fa1a25fc572cee Mon Sep 17 00:00:00 2001 From: timmy Date: Sat, 15 Aug 2026 21:31:42 +0000 Subject: [PATCH] fix: resume queued delivery on reconnect (Closes #917) --- frontend/session.js | 8 ++++++++ tests/test_dashboard_session_frontend.py | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/frontend/session.js b/frontend/session.js index debc694..d9a2b1d 100644 --- a/frontend/session.js +++ b/frontend/session.js @@ -36,6 +36,7 @@ root.fetch = boundary.fetch; const attach = () => { boundary.startActivityHeartbeat(); + boundary.startReconnectResume(); const button = root.document.getElementById('sign-out'); if (button) button.addEventListener('click', () => boundary.signOut()); const allDevicesButton = root.document.getElementById('sign-out-all'); @@ -387,6 +388,12 @@ }); } + function startReconnectResume() { + addActivityListener?.('online', async () => { + if (await refreshOfflineLease()) await resumeQueuedWork(); + }); + } + async function refreshOfflineLease() { try { const response = await sessionFetch(base + 'api/v1/session'); @@ -617,6 +624,7 @@ handleServiceWorkerMessage, refreshOfflineLease, resumeQueuedWork, + startReconnectResume, recordActivity, startActivityHeartbeat, }; diff --git a/tests/test_dashboard_session_frontend.py b/tests/test_dashboard_session_frontend.py index 729566c..80c3642 100644 --- a/tests/test_dashboard_session_frontend.py +++ b/tests/test_dashboard_session_frontend.py @@ -809,6 +809,28 @@ process.stdout.write(JSON.stringify(state)); assert result["workerMessages"] == [{"type": "stackchain-resume-outbox"}] +def test_reconnect_requests_queued_delivery_resume_after_offline_reload(): + result = run_session_scenario( + """ +boundary.startReconnectResume(); +state.responsePayload = {authenticated:true, expires_at:200000, idle_expires_at:150000}; +await state.activityListeners.online(); +await new Promise(resolve => setTimeout(resolve, 0)); +process.stdout.write(JSON.stringify(state)); +""" + ) + + assert result["requests"][0]["url"] == "/dashboard/api/v1/session" + assert result["workerMessages"] == [ + { + "type": "stackchain-session-lease", + "expiresAt": 200000, + "idleExpiresAt": 150000, + }, + {"type": "stackchain-resume-outbox"}, + ] + + @pytest.mark.anyio async def test_dashboard_loads_session_boundary_first_and_offers_sign_out(): html = await dashboard() -- 2.43.0