Request
Move validation out of the route body so the handler only describes successful work.
export async function POST(request: Request) {
const body = await request.json();
if (!body.email || !body.teamId) {
return Response.json({ error: "Invalid invite" }, { status: 400 });
}
return createInvite(body.teamId, body.email);
}const inviteInput = z.object({
teamId: z.string().min(1),
email: z.string().email(),
});
export const inviteMember = action(inviteInput, async (input) => {
return createInvite(input.teamId, input.email);
});State
Replace duplicated loading branches with a compact async state machine.
let loading = false;
let error: string | null = null;
let sent = false;
async function submit() {
loading = true;
error = null;
sent = false;
// ...
}type InviteState =
| { status: "idle" }
| { status: "sending" }
| { status: "sent" }
| { status: "failed"; error: string };
let state: InviteState = { status: "idle" };Response
Return one stable shape so callers do not need to inspect transport details.
const response = await fetch("/api/invite", {
method: "POST",
body: JSON.stringify(input),
});
if (!response.ok) {
throw new Error("Invite failed");
}const result = await inviteMember(input);
if (result.error) {
showError(result.error.message);
}
showInvite(result.data);