'Genericise' errors ready for +error.svelte upgrade to handle known errors

This commit is contained in:
2026-05-16 18:19:47 +01:00
parent 808b576df1
commit b51845528f
7 changed files with 97 additions and 60 deletions

View File

@@ -1,4 +1,4 @@
import type { HandleClientError } from "@sveltejs/kit";
import type { HandleClientError } from '@sveltejs/kit';
export const handleError: HandleClientError = ({ error }) => {
const err = error as any;
@@ -6,6 +6,6 @@ export const handleError: HandleClientError = ({ error }) => {
return {
message: err?.message || 'An unexpected application error occurred.',
code: err?.code || 'CRITICAL',
msg: err?.msg || 'UNHANDLED_EXCEPTION'
name: err?.name || 'UNHANDLED_EXCEPTION'
};
};

View File

@@ -1,5 +1,6 @@
import { OwlBoardClient, ValidationError, ApiError } from '@owlboard/owlboard-ts';
import { browser, dev } from '$app/environment';
import { error } from '@sveltejs/kit';
// Import the runes containing the API Key config Here...
@@ -18,6 +19,46 @@ export const OwlClient = new OwlBoardClient(
// API Key Here when ready!!!
);
export function ThrowApiError(e: any): void {}
export function ThrowApiError(e: unknown): never {
// Handle Request failure
if (e instanceof TypeError && e.message === 'Failed to fetch') {
throw error(503, {
message: 'Unable to connect to the OwlBoard server',
name: 'NETWORK_ERROR',
code: 'NETWORK_UNREACHABLE'
});
}
// Map ApiError 'code' values
if (e instanceof ApiError) {
let status = 500;
if (e.code === 'AUTH') {
status = 401;
} else if (e.code === 'NOT_FOUND') {
status = 404;
} else if (e.code === 'RATE_LIMIT') {
status = 421;
} else if (e.code === 'NETWORK_DISCONNECTED') {
status = 503;
} else if (e.code === 'VALIDATION') {
status = 400;
}
throw error(status, {
message: e.message || 'An operational error has occurred',
name: e.name || 'API_ERROR',
code: e.code || 'UNKNOWN_API_ERROR'
});
}
// Fallback for other error kind
const genericMessage = e instanceof Error ? e.message : 'An unexpected error occurred.';
throw error(500, {
message: genericMessage,
name: 'CRITICAL_ERROR',
code: 'INTERNAL_ERROR',
msg: 'UNHANDLED_EXCEPTION'
});
}
export { ValidationError, ApiError };

View File

@@ -15,7 +15,13 @@
import logoPlain from '$lib/assets/round-logo.svg';
import favicon from '$lib/assets/round-logo.svg';
import { IconHome, IconDialpad, IconSettings, IconHelp, IconDots } from '@tabler/icons-svelte-runes';
import {
IconHome,
IconDialpad,
IconSettings,
IconHelp,
IconDots
} from '@tabler/icons-svelte-runes';
onMount(async () => {
LOCATIONS.init();

View File

@@ -18,11 +18,7 @@
class:animate={isSpinning}
aria-label="Spin the OwlBoard logo"
>
<img
class="logo-img"
src={logo}
alt="OwlBoard Logo"
/>
<img class="logo-img" src={logo} alt="OwlBoard Logo" />
</button>
</div>
@@ -76,8 +72,6 @@
width: clamp(80px, 20vw, 200px);
}
@keyframes owl-spin {
0% {
transform: rotate(0deg);

View File

@@ -25,7 +25,10 @@
console.log(e);
errorState = { status: 20, message: e.message };
} else {
errorState = { status: 0, message: `Unknown Error: ${e instanceof Error ? e.message : String(e)}` };
errorState = {
status: 0,
message: `Unknown Error: ${e instanceof Error ? e.message : String(e)}`
};
}
} finally {
resultsLoaded = true;
@@ -45,7 +48,10 @@
console.log(e);
errorState = { status: 20, message: e.message };
} else {
errorState = { status: 0, message: `Unknown Error: ${e instanceof Error ? e.message : String(e)}` };
errorState = {
status: 0,
message: `Unknown Error: ${e instanceof Error ? e.message : String(e)}`
};
}
} finally {
resultsLoaded = true;

View File

@@ -1,4 +1,4 @@
import { OwlClient, ApiError, ValidationError } from '$lib/owlClient';
import { OwlClient, ApiError, ValidationError, ThrowApiError } from '$lib/owlClient';
import type { ApiTrainsTrainByHeadcode } from '@owlboard/owlboard-ts';
import type { PageLoad } from './$types';
import { error } from '@sveltejs/kit';
@@ -10,31 +10,21 @@ export const load: PageLoad = async ({ fetch, url }) => {
const date: string | Date = dateParam === '' || dateParam === null ? new Date() : dateParam;
if (!headcode) {
throw error(400, {
message: 'Headcode not provided',
owlCode: 'INVALID_DATA'
});
}
// Validation removed, handled by the API Client Lib
// Declared outside of the try so that it can be used in both the try and catch blocks
let results: ApiTrainsTrainByHeadcode.TrainByHeadcodeResponse[];
try {
const response = await OwlClient.trains.getByHeadcode(headcode, date, toc, fetch);
const response = await OwlClient.trains.getByHeadcode(headcode || '', date, toc, fetch);
let title = !!headcode ? headcode.toUpperCase() : 'Error';
results = response.data;
return {
title: headcode.toUpperCase(),
title: title,
results: results
};
} catch (e: unknown) {
if (e instanceof TypeError && e.message === 'Failed to fetch') {
error(503, {
message: 'Cannot connect to the OwlBoard server',
owlCode: 'NETWORK_DISCONNECTED'
});
}
throw e;
ThrowApiError(e);
}
};