fix(errors): surface previously-silent async failures (DP1/DP4/DP6)

Several fire-and-forget promises failed silently:
- RoomInput slash-command exe() rejections reset the editor as if they
  succeeded; now caught and shown via an error toast.
- Favourite / low-priority room-tag toggles (setRoomTag/deleteRoomTag)
  swallowed rejections; now surfaced via the same error toast.
- Call-decline sendEvent(RTCDecline) was uncaught; now logged best-effort
  while the local UI still dismisses.

Adds a shared createErrorToast builder mirroring createDownloadToast.
/kick and /ban route through rateLimitedActions, whose to() helper
swallows non-429 errors, so those two can still resolve on failure — noted
in code; the top-level exe() catch covers everything that does reject.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 22:29:39 -04:00
co-authored by Claude Opus 4.8
parent 2614e6b92d
commit 8eb961b682
5 changed files with 66 additions and 10 deletions
+17
View File
@@ -27,6 +27,23 @@ export const createDownloadToast = (filename: string, iconSrc?: IconSrc): ToastN
onClick: () => undefined,
});
// Build an error/system toast (e.g. a failed command or account action). Mirrors
// createDownloadToast: folds-free (icon src passed in), empty roomId + no-op
// onClick so a click only dismisses (never navigates to a room).
export const createErrorToast = (
body: string,
iconSrc?: IconSrc,
displayName = 'Something went wrong',
): ToastNotif => ({
id: `error-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
displayName,
body,
roomName: '',
roomId: '',
iconSrc,
onClick: () => undefined,
});
const baseAtom = atom<ToastNotif[]>([]);
// Write-only setter used in ClientNonUIFeatures