fix(commands): /kick and /ban failures are no longer silent (#216)
rateLimitedActions now collects non-429 failures (and a 429 that exhausted its retries) and returns them instead of swallowing them; existing callers ignore the return. /kick and /ban turn the list into a CommandError whose message names who and why, using the server's own sentence (MatrixError.data.error), never the URL-bearing toString(); RoomInput's toast shows it verbatim. Verified headless as a non-moderator: '/kick @alice' → "Could not kick @alice:localhost: You cannot kick user @alice:localhost."; '/ban @nobody @alice' → "Could not ban @nobody:localhost, @alice:localhost: You don't have permission to ban". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
@@ -113,7 +113,14 @@ import {
|
||||
} from './msgContent';
|
||||
import { getMemberName, getMentionContent, trimReplyFromBody } from '../../utils/room';
|
||||
import { CommandAutocomplete } from './CommandAutocomplete';
|
||||
import { Command, SHRUG, TABLEFLIP, UNFLIP, useCommands } from '../../hooks/useCommands';
|
||||
import {
|
||||
Command,
|
||||
CommandError,
|
||||
SHRUG,
|
||||
TABLEFLIP,
|
||||
UNFLIP,
|
||||
useCommands,
|
||||
} from '../../hooks/useCommands';
|
||||
import { mobileOrTablet } from '../../utils/user-agent';
|
||||
import { useElementSizeObserver } from '../../hooks/useElementSizeObserver';
|
||||
import { ReplyLayout, ThreadIndicator } from '../../components/message';
|
||||
@@ -665,16 +672,16 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
||||
const commandContent = commands[commandName as Command];
|
||||
if (commandContent) {
|
||||
// Fire-and-forget by design (the editor resets immediately for UX), but
|
||||
// surface a rejection instead of failing silently. NOTE: /kick and /ban
|
||||
// route through rateLimitedActions (utils/matrix.ts), whose to() helper
|
||||
// swallows non-429 errors, so those two commands can still resolve even
|
||||
// when the underlying kick/ban failed — this catch only covers errors
|
||||
// that actually reject out of exe().
|
||||
// surface a rejection instead of failing silently. /kick and /ban
|
||||
// throw a CommandError whose message already names who and why
|
||||
// (#216); anything else gets the generic sentence.
|
||||
commandContent.exe(plainText).catch((err) => {
|
||||
console.error(`Failed to run /${commandName} command:`, err);
|
||||
setToast(
|
||||
createErrorToast(
|
||||
`The /${commandName} command failed. Please try again.`,
|
||||
err instanceof CommandError
|
||||
? err.message
|
||||
: `The /${commandName} command failed. Please try again.`,
|
||||
Icons.Warning,
|
||||
'Command failed',
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user