Skip to content

fix: honor Resend error envelope and abort refresh on logout - #80

Merged
Wifsimster merged 1 commit into
mainfrom
claude/vibrant-albattani-6CrBL
Jun 3, 2026
Merged

fix: honor Resend error envelope and abort refresh on logout#80
Wifsimster merged 1 commit into
mainfrom
claude/vibrant-albattani-6CrBL

Conversation

@Wifsimster

Copy link
Copy Markdown
Owner

Summary

Two real defects surfaced by a senior-dev pass over the codebase.

1. api/notifications: silent Resend delivery rejections (HIGH)

notifyNewTicket only caught thrown errors from Resend's emails.send, but Resend resolves with { data: null, error } on delivery rejections (unverified sender, blocked recipient, suppressed address, etc.). Those failures were silently treated as success — the widget POST returned 201, no email was sent, and no log told the operator why the inbox was empty.

sendTestEmail already mirrors the envelope check, so this aligns the fire-and-forget notification path with the operator-driven probe. Same swallow-and-log posture: returns false instead of true, logs the error object.

Added a test ('returns false and logs when Resend resolves with an error envelope') that pins the new behavior — fake Resend returns { data: null, error: { message: 'Domain is not verified' } }, and notifyNewTicket is expected to resolve false.

2. dashboard/AuthContext: logout race re-authenticates the user (MEDIUM)

logout() did not abort the in-flight /me + /projects refresh controller. The race:

  1. refresh() is in flight (e.g. mount probe, or background re-fetch).
  2. User clicks Logout.
  3. api.logout() runs and resolves.
  4. setState({ status: 'unauthenticated' }) flips the UI.
  5. The pending refresh — issued before the cookie was cleared — comes back 200 OK and writes { status: 'authenticated', ... } on top.

Net effect: the dashboard bounces back to the inbox right after logout. The fix aborts the controller before the state flip so any late refresh response is dropped.

Test plan

  • pnpm typecheck — clean across all packages
  • pnpm test — 90/90 pass (1 new test in notifications.test.ts)
  • pnpm turbo run build — all packages build
  • Manual: configure Resend with a deliberately unverified sender, submit a widget ticket, confirm the server logs [koe/api] notifyNewTicket rejected by Resend instead of going silent
  • Manual: click Logout while the dashboard is mid-refresh, confirm the login screen sticks

Generated by Claude Code

Two real defects surfaced by a senior-dev pass over the codebase:

api/notifications: notifyNewTicket only caught thrown errors from
Resend's `emails.send`, but Resend resolves with `{ data: null, error }`
on delivery rejections (unverified sender, blocked recipient, ...).
Those failures were silently treated as success — the widget POST
returned 201, no email was sent, and no log told the operator why.
sendTestEmail already mirrors the envelope check, so this aligns the
fire-and-forget notification path with the operator-driven probe.

dashboard/AuthContext: logout did not abort the in-flight /me +
/projects refresh. A response that landed during the logout round-trip
could resolve after the state flip and re-mark the user authenticated,
bouncing them back to the inbox instead of the login page. Cancel the
controller before the state flip so any late refresh is a no-op.

https://claude.ai/code/session_01BJZtxNxxeWYbJcUhUdjwX5
@Wifsimster
Wifsimster marked this pull request as ready for review June 3, 2026 17:09
@Wifsimster
Wifsimster merged commit d29b111 into main Jun 3, 2026
1 check passed
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.

2 participants