Skip to content

feat(ui): extract auth to auth-store + harden authFetch (W5.3) - #434

Merged
krisarmstrong merged 3 commits into
mainfrom
refactor/stem-auth-store
Jun 15, 2026
Merged

feat(ui): extract auth to auth-store + harden authFetch (W5.3)#434
krisarmstrong merged 3 commits into
mainfrom
refactor/stem-auth-store

Conversation

@krisarmstrong

Copy link
Copy Markdown
Collaborator

What

Wave 5.3 of the stem App.tsx decomposition: extract all authentication state and flows out of the god component into a dedicated Zustand auth-store, and bundle the always-latest toolchain sweep that landed alongside it.

Two commits (squash-friendly but separated for review):

1. chore(tooling) — toolchain to latest

  • Biome 2.4.16 → 2.5.0 (biome migrate applied: recommendedpreset, nursery-rule renames)
  • TypeScript build: tsc -btsgo --build (@typescript/native-preview; typescript dep dropped). Types/language unchanged — only the typecheck+build binary.
  • Vite 8.0.14 → 8.0.16, Vitest 4.1.7 → 4.1.8, Node 26.2.0 → 26.3.0 (npm pinned 11.17.0)
  • golangci-lint golden config v2.12.1 → v2.12.2; commitlint 21, lint-staged 17.0.7; exact-pin remaining ^ ranges

2. feat(ui) — auth-store wiring (part 2/2)

Part 1 (auth-store.ts + hardened module authFetch + 14 tests) landed in 58bc4fd. This wires App.tsx to it:

  • App reads auth state via store selectors; login/MFA/logout/setup/recovery flows dispatch to store actions. Inline authFetch/expireSession/refresh/retry stack removed (now module-level in the store).
  • Added cancelMfa store action (+ unit test) for the MFA "Use different account" path.
  • Removed dead code left mid-migration: setState shims, AUTH_FLAG_KEY, local Setup/RecoveryStatus interfaces, unused imports.
  • Fixed two breakages from the in-progress state: SetupWizard onLogin pointed at a removed performLogin (→ handleSetupLogin); queryFns called module authFetch without importing it.
  • connected stays App-local, reconciled off isAuthenticated + the interfaces query; queryFns thread the React Query abort signal.

Validation

  • biome check src/ — clean (2.5.0)
  • tsgo --build --noEmit — clean
  • vitest run198/198 (incl. new cancelMfa test)
  • vite build — green, embedded to internal/api/ui/
  • gitleaks — no leaks

Notes for review

  • Security-sensitive (auth): the hardened authFetch semantics (single-flight refresh, cancel-then-clear cache, 401 refresh+retry, 403 PERMISSION_DENIED vs CSRF branching) were cross-model reviewed in part 1 and are unchanged here.
  • The tsc → tsgo swap is a dev-preview compiler now driving the build — worth a deliberate look.

🚫 Auto-merge intentionally NOT armed — owner sign-off gate.

Kris Armstrong added 3 commits June 15, 2026 12:27
Security-critical core of the auth extraction, built standalone + proven by
tests before the App.tsx wiring. Cross-model (Codex) reviewed.

auth-store.ts (Zustand, not persisted; isAuthenticated seeded from the
localStorage flag): login/verifyMfa/performLogin/logout/expireSession +
setup/recovery state + checkStatuses. Module-level authFetch for RQ queryFns.

Hardening over the previous inline implementation:
- single-flight refresh (concurrent 401s share one in-flight refresh)
- cancelQueries() THEN clear() on teardown (no late request can repopulate
  cross-session cache)
- 401: refresh+retry; only refresh-failure or a still-401 retry expires —
  a retried 5xx/4xx returns to the caller
- 403: {code:PERMISSION_DENIED} (authz denial, valid session) returns to the
  caller; any other 403 (CSRF/unknown, plain-text) expires the session
- credentials:'include' always; tokens never read; FormData/signal preserved

14 unit tests cover all of the above (single-flight, cache purge, retry
semantics, 403 branching, request-shape). tsc + biome clean.

Part 2 (App.tsx wiring) follows; this commit is intentionally unused until then.
Always-latest bump across the JS/Go toolchain:
- Biome 2.4.16 -> 2.5.0 (biome migrate: recommended->preset + nursery renames)
- TypeScript build: tsc -b -> tsgo --build (@typescript/native-preview); drop typescript dep
- Vite 8.0.14 -> 8.0.16, Vitest 4.1.7 -> 4.1.8
- Node 26.2.0 -> 26.3.0, npm pinned 11.17.0 (+ packageManager)
- golangci-lint golden config v2.12.1 -> v2.12.2
- commitlint 20.5.3 -> 21.0.2, lint-staged 17.0.7; exact-pin remaining ^ ranges
Complete the auth decomposition: App.tsx reads auth state via auth-store
selectors and dispatches flows through store actions; the module-level
authFetch backs the React Query queryFns.

- Replace inline login/MFA/logout/setup/recovery handlers + the local
  authFetch/expireSession/refresh stack with thin store dispatches.
- Add cancelMfa store action (+ unit test) for the MFA 'Use different
  account' path; drop the dead setState shims, AUTH_FLAG_KEY, the local
  Setup/RecoveryStatus interfaces, and now-unused imports.
- Fix two breakages from the in-progress migration: SetupWizard onLogin
  pointed at a removed performLogin (-> handleSetupLogin); queryFns used
  module authFetch without importing it.
- connected stays App-local, reconciled off isAuthenticated + the
  interfaces query; queryFns thread the React Query abort signal.

Validated: biome 2.5.0 clean, tsgo typecheck clean, vitest 198/198,
vite build green.
@github-actions

Copy link
Copy Markdown
Contributor

License Compliance Report

All dependencies pass license compliance checks

Go Dependencies

  • Unknown: 31 package(s)
  • MIT: 26 package(s)
  • BSD-3-Clause: 16 package(s)
  • Apache-2.0: 11 package(s)
  • BSD-2-Clause: 1 package(s)

npm Dependencies

See full report in workflow artifacts

Allowed Licenses: MIT, Apache-2.0, BSD-*, ISC, CC0-1.0, MPL-2.0
Forbidden: GPL, AGPL, SSPL (strong copyleft)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant