fix(auth): recover browser sessions after server restart - #749
Conversation
Confirm CodeNomad authentication after API 401s or event-stream disconnects and explain expired browser sessions in an in-page login dialog. A server restart invalidates its memory-only sessions even when credentials remain valid; avoid misdiagnosing upstream OpenCode authorization or network outages. Coalesce bounded status checks and fence late responses across login. Restore the event stream after reauthentication while leaving the composer mounted and never replaying failed application mutations. Reuse native login endpoints, shared square dialog styling and all ten locales. Validate with real authentication routes and replaced session managers in browser fixtures: SSE-triggered recovery, drafts and attachments, invalid credentials, upstream 401s, outages, overlapping alerts, narrow screens and cookies renewed elsewhere. Add unit coverage for probe/login races and restoration; adjacent SDK/event/draft regressions and UI typecheck pass.
Address gatekeeper findings by capturing live workspace state before restart reconciliation removes unavailable instances, including fresh pages without a startup snapshot and projects opened after that snapshot. Reopening the folder under a new backend identity restores drafts and attachments through existing preservation hydration. Suspend the generic alert's modal surface during authentication recovery while retaining its pending payload and input state. Fence deferred focus so alerts arriving after expiry cannot steal pointer or keyboard ownership from the visible login form. Extend browser coverage to the real capture and instance lifecycle: remove the old composer after an empty post-restart inventory, reopen with a new ID, and verify recovered content. Exercise late generic alerts and failed-mutation non-replay. All four browser scenarios and 33 targeted unit regressions pass.
|
I checked the failed CI jobs against the pre-PR code. Both system-message search failures reproduce on the exact base commit, and the same failures appear in the earlier run https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/35753233159. That run also has the same native migration assertion failure: OpenCode 2.0.14 adds All four new auth-recovery browser scenarios passed in the full CI run. The minimum/latest runtime contracts and both Tauri test jobs passed. I reran the Windows pruning job, which exited without an assertion or useful error in its log. |
|
I completed the gatekeeper loop: both initial P1 findings were fixed, and subsequent reviews found no remaining actionable code issues. The Windows pruning rerun still exits without a diagnostic at UI startup. I ran the complete isolated native/UI fixture successfully on Windows with OpenCode 2.0.14, then repeated it with Node 24.20.0, the exact CI version. Both passed busy-state handling, individual/group/response/session cleanup, persistence, reload and plugin lifecycle checks. The CI-only exit remains undiagnosed; I am not treating CI as fully green. I am admin-merging the reviewed c64a06d head with these limitations recorded. The other red checks are the pre-existing search and migration failures documented above. |
Fixes #509.
I added an in-page login form when CodeNomad confirms that the browser session is no longer valid. API failures and event-stream disconnects trigger a bounded auth-status check; upstream OpenCode 401s and network outages do not trigger a misleading login prompt. Successful login reconnects events without reloading the page or replaying failed actions.
I also preserve live workspace drafts before restart reconciliation removes old backend workspace IDs. Reopening the project restores that state, including on a fresh page with no startup snapshot. Generic alerts wait behind authentication recovery without losing their pending state.
Validation
Review
The first independent gatekeeper review found two P1 issues: restart reconciliation could discard fresh-page drafts, and a late alert could block the login form. I fixed both and added regressions. The second pass reported zero actionable findings and independently passed the four browser scenarios and thirteen focused unit tests.