fix(api): read the error code before the status

A read-failure primitive decided from the status alone, so a 401 from a
step-up or re-proof gate would have read as an ended session and sent
the reader to sign-in. The code now decides first and the status is the
fallback for codes it does not know.

The two invitation routes answer an unknown name or e-mail with
sharing.invite.no_account. Both have a second 404 with a different next
step, and since every error now carries a code the clients match on it
instead of on the status. The status defaults move into a module the
client can import, and the contract text no longer says these arms
carry no code.
This commit is contained in:
Marc-André Bombeck committed 2026-10-20 09:48:15 +02:00
1 parent 0057b03699
commit c300574a8e
20 files changed
+212 -128

No files matched your search

@@ -335,9 +335,12 @@ describe("a refused invitation keeps what was typed", () => {
expect(inviteErrorKey(new TypeError("Failed to fetch"))).toBe(
"recordSharing.invite.errorOffline",
);
expect(inviteErrorKey(apiError(404))).toBe(
expect(inviteErrorKey(apiError(404, "sharing.invite.no_account"))).toBe(
"recordSharing.invite.errorNoAccount",
);
expect(inviteErrorKey(apiError(404, "http.not_found"))).toBe(
"recordSharing.invite.errorFailed",
);
expect(inviteErrorKey(apiError(409, "sharing.invite.duplicate"))).toBe(
"recordSharing.invite.errorDuplicate",
);
@@ -188,7 +188,7 @@ const TOKEN_IN_ERROR_422: Record<string, string> = {
"src/app/api/auth/me/health-score-config/route.ts health-score-config.body.invalid_json":
"The published 422 description spells this exact body out as what a non-JSON request earns. It is the one operation whose contract promises the token, so the token is what it answers with.",
"src/app/api/coach/reminder-suggestions/route.ts coach.suggestion.unknownCadence":
"Predates this sweep and carries no `meta.errorCode` yet; the Coach reminder surfaces move as one piece or not at all.",
"Predates this sweep and carries only the status default code; the Coach reminder surfaces move as one piece or not at all.",
"src/app/api/coach/reminders/route.ts coach.reminder.invalidWhen":
"Predates this sweep, same surface.",
"src/app/api/coach/reminders/[id]/route.ts coach.reminder.invalidWhen":