fix(gui-app): survive auth changes during the router's initial load + hold TanStack router at pre-refresh pins - #1136
Conversation
On router-core >= 1.171.16, invalidate() during a load retires the active transaction. When that load is the very first one (no resolution has ever completed), nothing reschedules it: the router stays pending with no committed matches and the app renders a permanently blank screen. Mobile cold launches hit this window on nearly every fresh install, where the stored-token validation flips auth mid initial load. bindAuthInvalidation now detects the uncommitted window via resolvedLocation (matches is not a commit signal: slow loads publish provisional pending matches after defaultPendingMs) and routes the auth change through router.load() first, invalidating once the load settles. Recoveries are coalesced to one per uncommitted window since load() aborts its predecessor transaction rather than joining it. Signed-off-by: Pranshu Gupta <76090263+pranshugupta54@users.noreply.github.com>
…ions The 1.170.18 -> 1.170.25 range (router-core 1.171.15 -> 1.171.21) contains router-core's lane-scheduler rewrite, which is still churning upstream (1.171.22 landed another ~1600-line pass over the same area). Its invalidation-retires-active-work semantics orphaned the router's initial load on mobile cold launches. The bindAuthInvalidation guard neutralizes that specific defect, but the rewrite is too unsettled to ship on; hold the family at the last field-proven set until a routine dependency refresh can revalidate it: - @tanstack/react-router 1.170.18 (exact - carries router-core 1.171.15 as an exact transitive pin) - @tanstack/router-plugin 1.168.23 (exact - its newer releases require react-router ^1.170.25, which would split the resolution into two router-core copies) Also restores the isTransitioning check in history-prune-provider that was adapted away when the newer router dropped that state field. Signed-off-by: Pranshu Gupta <76090263+pranshugupta54@users.noreply.github.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI (base), Organization UI (inherited) Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Summary by CodeRabbit
WalkthroughThe router now recovers unresolved initial loads before invalidation, coalesces auth changes, and invalidates after recovery settles. Tests cover unit and real-router flows. Navigation pruning detects transitioning states, and TanStack Router versions are pinned. ChangesAuth invalidation recovery
TanStack Router version pinning
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant AuthStore
participant bindAuthInvalidation
participant TanStackRouter
participant RouterProvider
AuthStore->>bindAuthInvalidation: auth transition
bindAuthInvalidation->>TanStackRouter: inspect pending state
bindAuthInvalidation->>TanStackRouter: call load()
TanStackRouter-->>RouterProvider: settle initial route
bindAuthInvalidation->>TanStackRouter: call invalidate()
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@clients/gui-app/src/__tests__/router-auth-invalidation.integration.test.tsx`:
- Around line 56-67: Replace the local waitUntil helper and fixed timeout in the
router authentication integration test with Testing Library waitFor, waiting on
the relevant router state conditions. Import act and wrap both
useAuthStore.setState calls, including the gate release, so synchronous router
updates and mounted RouterProvider renders are flushed within React’s act
environment; retain the existing assertions and convergence behavior.
- Line 160: Register the test teardown immediately after
bindAuthInvalidation(adapter) creates unsubscribe, using the repository’s
standard automatic cleanup mechanism to invoke unsubscribe regardless of
assertion outcomes. Remove the success-path-only unsubscribe call while
preserving the existing unmount cleanup behavior.
In `@clients/gui-app/src/__tests__/router-auth-invalidation.test.ts`:
- Around line 12-19: Update the version reference in the documentation comment
above bindAuthInvalidation to match the pinned `@tanstack/react-router` version,
1.170.18, or another explicitly verified range. Leave the described router-state
behavior unchanged.
- Around line 33-37: Update the comments in
clients/gui-app/src/__tests__/router-auth-invalidation.test.ts:33-37 to describe
recovery coalescing as per-binding closure state from bindAuthInvalidation, not
module-scoped state. In
clients/gui-app/src/__tests__/router-auth-invalidation.integration.test.tsx:106-119,
remove the claim that state.resolvedLocation is required and the
always-present-key justification, while preserving the adapter and spy
justification.
In `@clients/gui-app/src/providers/history-prune-provider.tsx`:
- Around line 102-109: Bound the retry loop in flush when isRouterLoadInFlight
reports true, adding a termination or abort path after a finite number of
requestAnimationFrame retries while preserving normal pruning once the router
becomes idle. Add coverage for a persistently in-flight router state to verify
retries stop and no permanent animation-frame loop remains.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 5ee4039b-e4b0-4794-931a-df38631b2720
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (5)
clients/gui-app/src/__tests__/router-auth-invalidation.integration.test.tsxclients/gui-app/src/__tests__/router-auth-invalidation.test.tsclients/gui-app/src/providers/history-prune-provider.tsxclients/gui-app/src/router.tsxpackage.json
- drive the mounted-router assertions through Testing Library's waitFor and wrap store writes in act() instead of hand-rolled timers - register unsubscribe via onTestFinished so a failed assertion cannot leak the auth listener into the unmounted tree - correct the version cite (behavior observed on 1.170.25; repo pins 1.170.18) and two stale doc claims (recovery is per-binding closure state; resolvedLocation is optional on the interface) Signed-off-by: Pranshu Gupta <76090263+pranshugupta54@users.noreply.github.com>
Signed-off-by: Pranshu Gupta <76090263+pranshugupta54@users.noreply.github.com>
## Summary - Refreshes compatible open-source Bun dependencies and regenerates the lockfile, including TipTap 3.30.1, Electron 42.9.0, PostHog 1.417.0, shadcn 4.17.0, and supporting UI/tooling patches. - Preserves the exact TanStack Router versions restored by #1136 after the mobile cold-launch blank-screen regression; neither direct dependency nor the transitive router-core pin changes in this refresh. ## Still held after audit - `@tanstack/react-router` remains exactly `1.170.18`, `@tanstack/router-plugin` remains exactly `1.168.23`, and React Router continues to pin `@tanstack/router-core` at `1.171.15`. They must move together only after the initial-load scheduler regression is proven fixed. - Electron 43, Nx 23, ESLint 10, TypeScript 7, jsdom 30, motion 13, and undici 8 remain deliberate major-version holds. - Exact Sentry, Radix, Pierre, Legend, Dagre, and related compatibility pins remain unchanged. ## Verification - Bun 1.3.12 install and `bun install --frozen-lockfile` passed with no lockfile changes. - `bun outdated --recursive --no-progress` has no remaining eligible OSS rows; every reported delta is a deliberate hold. - `git diff --check` passed, with no TanStack Router-family changed lines in either the manifest or lockfile. - The commit-time canonical pre-commit hook passed affected build, compile, lint, format, JSON, secret, and DCO checks. Signed-off-by: Hardik Shingala <hardik@traycer.ai>
## Summary - update `posthog-js` from `^1.417.0` to `^1.417.1` - update `shadcn` from `^4.17.0` to `^4.18.0` - refresh the Bun lockfile ## Still held after audit - keep `@tanstack/react-router` at exact `1.170.18` and `@tanstack/router-plugin` at exact `1.168.23`; #1136 reverted their prior update after a permanent blank screen on mobile cold launch - keep the corresponding reverted router-core/history resolutions unchanged - leave out-of-range majors and deliberate exact/vendor pins unchanged ## Verification - `bun install --frozen-lockfile` - `bun outdated` audit - final `bun install` reported no changes - `git diff --check` - pre-commit affected build, compile, lint, and format checks Signed-off-by: Hardik Shingala <hardik@traycer.ai>
What
Two commits, one failure mode: fresh mobile installs of the Capacitor app booted to a permanently blank screen.
bindAuthInvalidation) — on cold launch, the auth status flips (stored tokens validating) while the router's initial load is still uncommitted. On router-core ≥1.171.16,invalidate()in that window retires the in-flight load and nothing reschedules it:status: "pending", zero committed matches, forever — no error anywhere. The binding now detects the uncommitted window viaresolvedLocation(matchesis not a commit signal — slow loads publish provisional pending matches afterdefaultPendingMs) and routes the auth change throughrouter.load()first, invalidating once it settles; recoveries are coalesced to one per window sinceload()aborts its predecessor transaction. Behavior on the held router version is unchanged (recheck lands a few ms later).react-router@1.170.18(exact; pins core 1.171.15 exactly) +router-plugin@1.168.23(exact; newer plugin requires^1.170.25and splits the resolution into two router-core copies). Thehistory-prune-provideradaptation from chore: refresh bun dependencies #1109 is restored to match. The guard stays regardless — it makes the pattern safe on any version, including future re-bumps.Verification
RouterProvideragainst the pinned library (slow uncommitted first load pastpendingMs→ real auth flip → converges; fails without the guard).matches; un-coalesced recovery fan-out) — both fixed and re-verified; final pass clean on auth flows, redirect loops, deep links, desktop multi-window, and hydration paths.Notes
load()revived it).Cc @hdkshingala