Auth frontend: login, verify, session, and logout#48
Conversation
- apiFetch now unwraps the ApiResponder envelope (typed payloads, server-authored error messages) and states the cookie contract with credentials: same-origin; sample MSW mock updated to match - New features/auth/: Login page (email -> generic check-your-email panel), Verify page (POSTs the emailed token once on mount with a StrictMode guard; routes shell accounts to /sign-up), and hooks — useSession (moved from lib/api as its comment mandated; 401 resolves to null), useRequestLink, useVerifyMagicLink, useLogout - RequireAuth redirects signed-out visitors to /login and incomplete profiles to /sign-up; AppLayout gains a Log out button - Router mounts /login and /auth/verify under the public layout - Test infra: auth MSW handlers composed into the server, MemoryRouter initialEntries support; page + guard tests cover the happy paths, expired links, and shell redirects Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
|
Graphite Automations"Request reviewers once CI passes" took an action on this PR • (07/10/26)2 reviewers were added to this PR based on Henry Chen's automation. |
| } | ||
|
|
||
| return response.json() as Promise<T>; | ||
| return envelope?.payload as T; |
There was a problem hiding this comment.
Returns undefined when the backend sends a successful response without a payload field or with invalid JSON, but casts it as type T. If T is not nullable, downstream code will crash at runtime.
For example, if the server returns {success: true, message: "OK"} without payload, or if JSON parsing partially succeeds but produces an object without the payload key, envelope?.payload evaluates to undefined but is typed as T.
if (!envelope?.payload && response.ok) {
throw new ApiError(
response.status,
"Server returned success without payload"
);
}
return envelope.payload as T;Alternatively, ensure the type system reflects that payload can be undefined: return envelope?.payload as T | undefined; and update call sites to handle undefined.
| return envelope?.payload as T; | |
| if (!envelope?.payload && response.ok) { | |
| throw new ApiError( | |
| response.status, | |
| "Server returned success without payload" | |
| ); | |
| } | |
| return envelope!.payload as T; | |
Spotted by Graphite
Is this helpful? React 👍 or 👎 to let us know.




server-authored error messages) and states the cookie contract with
credentials: same-origin; sample MSW mock updated to match
panel), Verify page (POSTs the emailed token once on mount with a
StrictMode guard; routes shell accounts to /sign-up), and hooks —
useSession (moved from lib/api as its comment mandated; 401 resolves
to null), useRequestLink, useVerifyMagicLink, useLogout
profiles to /sign-up; AppLayout gains a Log out button
initialEntries support; page + guard tests cover the happy paths,
expired links, and shell redirects
Co-Authored-By: Claude Fable 5 noreply@anthropic.com