feat: root error boundary and network-error normalisation

A load() that rethrew (e.g. the profile overview) fell through to SvelteKit's
bare default error page, and a connection-refused fetch rejected as a raw
TypeError that blanked the view. Wrap fetch network failures in the client as
ApiError(status 0, network_error) so callers handle them uniformly, and add a
root +error.svelte with a friendly message plus Try again / Go home actions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-11 14:47:41 +02:00
parent d779fa2b97
commit 32d0a7e13b
5 changed files with 142 additions and 2 deletions

View File

@@ -103,7 +103,21 @@ export async function request<T>(
// working. For same-origin requests this is a no-op compared to the
// default 'same-origin', so the same-origin happy path is
// unchanged.
const res = await fetch(`${BASE}${path}`, { credentials: 'include', ...init });
let res: Response;
try {
res = await fetch(`${BASE}${path}`, { credentials: 'include', ...init });
} catch {
// A network-level failure (connection refused, DNS, offline, blocked by
// CORS) rejects `fetch` with a bare TypeError instead of returning a
// response. Normalise it to an ApiError (status 0 = "no response reached
// us") so callers and SvelteKit load functions handle it uniformly
// instead of crashing on an unexpected TypeError.
throw new ApiError(
0,
'network_error',
'Could not reach the server. Check your connection and try again.'
);
}
if (!res.ok) {
let code = 'http_error';
let message = `${res.status} ${res.statusText}`;