Proper API error handling

This commit is contained in:
Christian Beutel
2025-01-03 18:05:25 +01:00
parent 9887874ad7
commit 46b5b94219
25 changed files with 366 additions and 251 deletions

View File

@@ -101,7 +101,7 @@
<div class="dropdown relative"> <div class="dropdown relative">
{#if unreadCount > 0} {#if unreadCount > 0}
<div <div
class="absolute -top-1 -right-1 text-sm rounded-full bg-content text-content-inverse w-4 aspect-square text-center" class="absolute -top-1 left-4 text-sm rounded-full bg-content text-content-inverse px-1 text-center"
> >
{unreadCount} {unreadCount}
</div> </div>

View File

@@ -1,5 +1,6 @@
import type { Activity } from "$lib/models/activity"; import type { Activity } from "$lib/models/activity";
import { ClientResponseError, type ListResult } from "pocketbase"; import { APIError } from "$lib/util/api_util";
import { type ListResult } from "pocketbase";
let activities: Activity[] = []; let activities: Activity[] = [];
@@ -14,7 +15,8 @@ export async function activities_index(author: string, page: number = 1, perPage
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const fetchedActivities: ListResult<Activity> = await r.json(); const fetchedActivities: ListResult<Activity> = await r.json();

View File

@@ -1,7 +1,7 @@
import { pb } from "$lib/pocketbase";
import type { Category } from "$lib/models/category"; import type { Category } from "$lib/models/category";
import { APIError } from "$lib/util/api_util";
import { type ListResult } from "pocketbase";
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
import { ClientResponseError, type ListResult } from "pocketbase";
export const categories: Writable<Category[]> = writable([]) export const categories: Writable<Category[]> = writable([])
@@ -9,9 +9,9 @@ export async function categories_index(f: (url: RequestInfo | URL, config?: Requ
const r = await f('/api/v1/category', { const r = await f('/api/v1/category', {
method: 'GET', method: 'GET',
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const response: ListResult<Category> = await r.json(); const response: ListResult<Category> = await r.json();

View File

@@ -1,7 +1,8 @@
import { Comment } from "$lib/models/comment"; import { Comment } from "$lib/models/comment";
import type { Trail } from "$lib/models/trail"; import type { Trail } from "$lib/models/trail";
import { pb } from "$lib/pocketbase"; import { pb } from "$lib/pocketbase";
import { ClientResponseError, type ListResult } from "pocketbase"; import { APIError } from "$lib/util/api_util";
import { type ListResult } from "pocketbase";
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
export const comments: Writable<Comment[]> = writable([]) export const comments: Writable<Comment[]> = writable([])
@@ -15,7 +16,8 @@ export async function comments_index(trail: Trail) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const fetchedComments: ListResult<Comment> = await r.json(); const fetchedComments: ListResult<Comment> = await r.json();
@@ -38,7 +40,8 @@ export async function comments_create(comment: Comment) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const model: Comment = await r.json(); const model: Comment = await r.json();
@@ -53,7 +56,8 @@ export async function comments_update(comment: Comment) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const model: Comment = await r.json(); const model: Comment = await r.json();
@@ -67,6 +71,7 @@ export async function comments_delete(comment: Comment) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
} }

View File

@@ -1,5 +1,6 @@
import type { Follow } from "$lib/models/follow"; import type { Follow } from "$lib/models/follow";
import { ClientResponseError, type ListResult } from "pocketbase"; import { APIError } from "$lib/util/api_util";
import { type ListResult } from "pocketbase";
let follows: Follow[] = []; let follows: Follow[] = [];
@@ -14,7 +15,8 @@ export async function follows_index(data: { follower?: string, followee?: string
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const fetchedFollows: ListResult<Follow> = await r.json(); const fetchedFollows: ListResult<Follow> = await r.json();
@@ -34,7 +36,8 @@ export async function follows_a_b(a: string, b: string, f: (url: RequestInfo | U
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const response: ListResult<Follow> = await r.json(); const response: ListResult<Follow> = await r.json();
@@ -48,7 +51,8 @@ export async function follows_counts(id: string, f: (url: RequestInfo | URL, con
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const response: { followers: number, following: number } = await r.json(); const response: { followers: number, following: number } = await r.json();
@@ -63,7 +67,8 @@ export async function follows_create(follow: Follow) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
} }
@@ -74,7 +79,8 @@ export async function follows_update(follow: Follow) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
} }
@@ -84,6 +90,7 @@ export async function follows_delete(follow: Follow) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
} }

View File

@@ -1,5 +1,6 @@
import type { ListShare } from "$lib/models/list_share"; import type { ListShare } from "$lib/models/list_share";
import { ClientResponseError, type ListResult } from "pocketbase"; import { APIError } from "$lib/util/api_util";
import { type ListResult } from "pocketbase";
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
export const shares: Writable<ListShare[]> = writable([]) export const shares: Writable<ListShare[]> = writable([])
@@ -13,7 +14,8 @@ export async function list_share_index(list: string, f: (url: RequestInfo | URL,
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const response: ListResult<ListShare> = await r.json(); const response: ListResult<ListShare> = await r.json();
@@ -31,7 +33,8 @@ export async function list_share_create(share: ListShare) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
} }
@@ -42,7 +45,8 @@ export async function list_share_update(share: ListShare) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
} }
@@ -52,6 +56,7 @@ export async function list_share_delete(share: ListShare) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
} }

View File

@@ -1,9 +1,10 @@
import { List, type ListFilter } from "$lib/models/list"; import { List, type ListFilter } from "$lib/models/list";
import type { Trail } from "$lib/models/trail"; import type { Trail } from "$lib/models/trail";
import { pb } from "$lib/pocketbase"; import { pb } from "$lib/pocketbase";
import { ClientResponseError, type ListResult } from "pocketbase"; import { type ListResult } from "pocketbase";
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
import { fetchGPX } from "./trail_store"; import { fetchGPX } from "./trail_store";
import { APIError } from "$lib/util/api_util";
let lists: List[] = [] let lists: List[] = []
export const list: Writable<List | null> = writable(null) export const list: Writable<List | null> = writable(null)
@@ -23,7 +24,8 @@ export async function lists_index(filter?: ListFilter, page: number = 1, perPage
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const fetchedLists: ListResult<List> = await r.json(); const fetchedLists: ListResult<List> = await r.json();
@@ -42,6 +44,12 @@ export async function lists_show(id: string, f: (url: RequestInfo | URL, config?
}), { }), {
method: 'GET', method: 'GET',
}) })
if (!r.ok) {
const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
}
const response = await r.json() const response = await r.json()
for (const trail of response.expand?.trails ?? []) { for (const trail of response.expand?.trails ?? []) {
@@ -50,9 +58,7 @@ export async function lists_show(id: string, f: (url: RequestInfo | URL, config?
} }
if (!r.ok) {
throw new ClientResponseError(response)
}
list.set(response); list.set(response);
@@ -73,7 +79,8 @@ export async function lists_create(list: List, avatar?: File) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const model: List = await r.json(); const model: List = await r.json();
@@ -89,11 +96,12 @@ export async function lists_create(list: List, avatar?: File) {
body: formData, body: formData,
}) })
if (r.ok) { if (!r.ok) {
return await r.json() const response = await r.json();
} else { throw new APIError(r.status, response.message, response.detail)
throw new ClientResponseError(await r.json())
} }
return await r.json();
} }
export async function lists_update(list: List, avatar?: File) { export async function lists_update(list: List, avatar?: File) {
@@ -103,7 +111,8 @@ export async function lists_update(list: List, avatar?: File) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const model: List = await r.json(); const model: List = await r.json();
@@ -120,7 +129,8 @@ export async function lists_update(list: List, avatar?: File) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
} }
@@ -133,7 +143,8 @@ export async function lists_add_trail(list: List, trail: Trail) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const model: List = await r.json(); const model: List = await r.json();
@@ -150,7 +161,8 @@ export async function lists_remove_trail(list: List, trail: Trail) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const model: List = await r.json(); const model: List = await r.json();
@@ -164,7 +176,8 @@ export async function lists_delete(list: List) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
} }

View File

@@ -1,5 +1,6 @@
import type { Notification } from "$lib/models/notification"; import type { Notification } from "$lib/models/notification";
import { ClientResponseError, type ListResult } from "pocketbase"; import { APIError } from "$lib/util/api_util";
import { type ListResult } from "pocketbase";
let notifications: Notification[] = []; let notifications: Notification[] = [];
@@ -14,7 +15,8 @@ export async function notifications_index(data: { recipient: string, seen?: bool
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const fetchedNotifications: ListResult<Notification> = await r.json(); const fetchedNotifications: ListResult<Notification> = await r.json();
@@ -29,10 +31,11 @@ export async function notifications_index(data: { recipient: string, seen?: bool
export async function notifications_mark_as_seen(notification: Notification) { export async function notifications_mark_as_seen(notification: Notification) {
let r = await fetch('/api/v1/notification/' + notification.id, { let r = await fetch('/api/v1/notification/' + notification.id, {
method: 'POST', method: 'POST',
body: JSON.stringify(notification), body: JSON.stringify({ seen: true }),
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
} }

View File

@@ -1,18 +1,18 @@
import { invalidateAll } from "$app/navigation"; import { invalidateAll } from "$app/navigation";
import { Settings } from "$lib/models/settings"; import { Settings } from "$lib/models/settings";
import { ClientResponseError } from "pocketbase"; import { APIError } from "$lib/util/api_util";
export async function settings_show(userId: string, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) { export async function settings_show(userId: string, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) {
const r = await f('/api/v1/settings/' + userId, { const r = await f('/api/v1/settings/' + userId, {
method: 'GET', method: 'GET',
}) })
if (!r.ok) {
const response = await r.json(); const response = await r.json();
if (r.ok) { throw new APIError(r.status, response.message, response.detail)
return response;
} else {
throw new ClientResponseError(response)
} }
const response = await r.json();
return response
} }
export async function settings_create(settings: Settings) { export async function settings_create(settings: Settings) {
@@ -21,11 +21,13 @@ export async function settings_create(settings: Settings) {
body: JSON.stringify(settings), body: JSON.stringify(settings),
}) })
if (r.ok) { if (!r.ok) {
return await r.json(); const response = await r.json();
} else { throw new APIError(r.status, response.message, response.detail)
throw new ClientResponseError(await r.json())
} }
return await r.json();
} }
export async function settings_update(settings: Settings) { export async function settings_update(settings: Settings) {
@@ -33,13 +35,14 @@ export async function settings_update(settings: Settings) {
method: 'POST', method: 'POST',
body: JSON.stringify(settings), body: JSON.stringify(settings),
}) })
if (!r.ok) {
const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
}
if (r.ok) {
await invalidateAll() await invalidateAll()
return await r.json(); return await r.json();
} else {
throw new ClientResponseError(await r.json())
}
} }
export async function settings_delete(settings: Settings) { export async function settings_delete(settings: Settings) {
@@ -47,9 +50,11 @@ export async function settings_delete(settings: Settings) {
method: 'DELETE', method: 'DELETE',
}) })
if (r.ok) { if (!r.ok) {
const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
}
return await r.json(); return await r.json();
} else {
throw new ClientResponseError(await r.json())
}
} }

View File

@@ -1,8 +1,9 @@
import { SummitLog, type SummitLogFilter } from "$lib/models/summit_log"; import { SummitLog, type SummitLogFilter } from "$lib/models/summit_log";
import { pb } from "$lib/pocketbase"; import { pb } from "$lib/pocketbase";
import { ClientResponseError, type ListResult } from "pocketbase"; import { type ListResult } from "pocketbase";
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
import { fetchGPX } from "./trail_store"; import { fetchGPX } from "./trail_store";
import { APIError } from "$lib/util/api_util";
export const summitLog: Writable<SummitLog> = writable(new SummitLog(new Date().toISOString().substring(0, 10))); export const summitLog: Writable<SummitLog> = writable(new SummitLog(new Date().toISOString().substring(0, 10)));
export const summitLogs: Writable<SummitLog[]> = writable([]); export const summitLogs: Writable<SummitLog[]> = writable([]);
@@ -21,7 +22,8 @@ export async function summit_logs_index(author: string, filter?: SummitLogFilter
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const fetchedSummitLogs: ListResult<SummitLog> = await r.json(); const fetchedSummitLogs: ListResult<SummitLog> = await r.json();
@@ -52,7 +54,8 @@ export async function summit_logs_create(summitLog: SummitLog, f: (url: RequestI
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
let model: SummitLog = await r.json(); let model: SummitLog = await r.json();
@@ -67,6 +70,11 @@ export async function summit_logs_create(summitLog: SummitLog, f: (url: RequestI
method: 'POST', method: 'POST',
body: formData, body: formData,
}) })
if (!r.ok) {
const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
}
} }
if (summitLog._photos && summitLog._photos.length) { if (summitLog._photos && summitLog._photos.length) {
@@ -81,13 +89,15 @@ export async function summit_logs_create(summitLog: SummitLog, f: (url: RequestI
method: 'POST', method: 'POST',
body: formData, body: formData,
}) })
if (!r.ok) {
const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
}
} }
if (r.ok) {
return model; return model;
} else {
throw new ClientResponseError(await r.json())
}
} }
export async function summit_logs_update(oldSummitLog: SummitLog, newSummitLog: SummitLog) { export async function summit_logs_update(oldSummitLog: SummitLog, newSummitLog: SummitLog) {
@@ -99,7 +109,8 @@ export async function summit_logs_update(oldSummitLog: SummitLog, newSummitLog:
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const formData = new FormData() const formData = new FormData()
@@ -123,23 +134,25 @@ export async function summit_logs_update(oldSummitLog: SummitLog, newSummitLog:
body: formData, body: formData,
}) })
if (r.ok) { if (!r.ok) {
return await r.json(); const response = await r.json();
} else { throw new APIError(r.status, response.message, response.detail)
throw new ClientResponseError(await r.json())
} }
return await r.json();
} }
export async function summit_logs_delete(summitLog: SummitLog) { export async function summit_logs_delete(summitLog: SummitLog) {
const r = await fetch('/api/v1/summit-log/' + summitLog.id, { const r = await fetch('/api/v1/summit-log/' + summitLog.id, {
method: 'DELETE', method: 'DELETE',
}) })
if (!r.ok) {
if (r.ok) { const response = await r.json();
return await r.json(); throw new APIError(r.status, response.message, response.detail)
} else {
throw new ClientResponseError(await r.json())
} }
return await r.json();
} }
function buildFilterText(filter: SummitLogFilter,): string { function buildFilterText(filter: SummitLogFilter,): string {

View File

@@ -1,5 +1,6 @@
import type { TrailShare } from "$lib/models/trail_share"; import type { TrailShare } from "$lib/models/trail_share";
import { ClientResponseError, type ListResult } from "pocketbase"; import { APIError } from "$lib/util/api_util";
import { type ListResult } from "pocketbase";
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
export const shares: Writable<TrailShare[]> = writable([]) export const shares: Writable<TrailShare[]> = writable([])
@@ -13,7 +14,8 @@ export async function trail_share_index(data: {trail?: string, user?: string}, f
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const response: ListResult<TrailShare> = await r.json(); const response: ListResult<TrailShare> = await r.json();
@@ -31,7 +33,8 @@ export async function trail_share_create(share: TrailShare) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
} }
@@ -42,7 +45,8 @@ export async function trail_share_update(share: TrailShare) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
} }
@@ -52,6 +56,7 @@ export async function trail_share_delete(share: TrailShare) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
} }

View File

@@ -6,10 +6,11 @@ import { deepEqual } from "$lib/util/deep_util";
import { getFileURL } from "$lib/util/file_util"; import { getFileURL } from "$lib/util/file_util";
import * as M from "maplibre-gl"; import * as M from "maplibre-gl";
import type { Hits } from "meilisearch"; import type { Hits } from "meilisearch";
import { ClientResponseError, type ListResult } from "pocketbase"; import { type ListResult } from "pocketbase";
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
import { summit_logs_create, summit_logs_delete, summit_logs_update } from "./summit_log_store"; import { summit_logs_create, summit_logs_delete, summit_logs_update } from "./summit_log_store";
import { waypoints_create, waypoints_delete, waypoints_update } from "./waypoint_store"; import { waypoints_create, waypoints_delete, waypoints_update } from "./waypoint_store";
import { APIError } from "$lib/util/api_util";
let trails: Trail[] = [] let trails: Trail[] = []
export const trail: Writable<Trail> = writable(new Trail("")); export const trail: Writable<Trail> = writable(new Trail(""));
@@ -26,12 +27,14 @@ export async function trails_index(perPage: number = 21, random: boolean = false
}) })
const response: ListResult<Trail> = await r.json() const response: ListResult<Trail> = await r.json()
if (r.ok) { if (!r.ok) {
const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
}
trails = response.items trails = response.items
return response.items; return response.items;
} else {
throw new ClientResponseError(response)
}
} }
export async function trails_search_filter(filter: TrailFilter, page: number = 1, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) { export async function trails_search_filter(filter: TrailFilter, page: number = 1, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) {
@@ -42,11 +45,13 @@ export async function trails_search_filter(filter: TrailFilter, page: number = 1
body: JSON.stringify({ q: filter.q, options: { filter: filterText, sort: [`${filter.sort}:${filter.sortOrder == "+" ? "asc" : "desc"}`], hitsPerPage: 12, page: page } }), body: JSON.stringify({ q: filter.q, options: { filter: filterText, sort: [`${filter.sort}:${filter.sortOrder == "+" ? "asc" : "desc"}`], hitsPerPage: 12, page: page } }),
}); });
if (!r.ok) {
const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
}
const result: { page: number, totalPages: number, hits: Hits<Record<string, any>> } = await r.json(); const result: { page: number, totalPages: number, hits: Hits<Record<string, any>> } = await r.json();
if (!r.ok) {
throw new ClientResponseError(result)
}
const trailIds = result.hits.map((h: Record<string, any>) => h.id); const trailIds = result.hits.map((h: Record<string, any>) => h.id);
@@ -61,13 +66,16 @@ export async function trails_search_filter(filter: TrailFilter, page: number = 1
}), { }), {
method: 'GET', method: 'GET',
}) })
if (!r.ok) {
const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
}
const response: ListResult<Trail> = await r.json() const response: ListResult<Trail> = await r.json()
if (r.ok) {
return { items: response.items, ...result }; return { items: response.items, ...result };
} else {
throw new ClientResponseError(response)
}
} }
export async function trails_search_bounding_box(northEast: M.LngLat, southWest: M.LngLat, filter?: TrailFilter, loadGPX: boolean = true) { export async function trails_search_bounding_box(northEast: M.LngLat, southWest: M.LngLat, filter?: TrailFilter, loadGPX: boolean = true) {
@@ -109,9 +117,15 @@ export async function trails_search_bounding_box(northEast: M.LngLat, southWest:
}), { }), {
method: 'GET', method: 'GET',
}) })
if (!r.ok) {
const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
}
const response = await r.json() const response = await r.json()
if (r.ok) {
if (loadGPX) { if (loadGPX) {
for (const trail of response.items) { for (const trail of response.items) {
const gpxData: string = await fetchGPX(trail); const gpxData: string = await fetchGPX(trail);
@@ -126,9 +140,7 @@ export async function trails_search_bounding_box(northEast: M.LngLat, southWest:
trails = response.items; trails = response.items;
return { trails: response.items, ...comparison }; return { trails: response.items, ...comparison };
} else {
throw new ClientResponseError(response)
}
} }
@@ -138,12 +150,14 @@ export async function trails_show(id: string, loadGPX?: boolean, f: (url: Reques
}), { }), {
method: 'GET', method: 'GET',
}) })
const response = await r.json()
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(response) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const response = await r.json()
if (loadGPX) { if (loadGPX) {
if (!response.expand) { if (!response.expand) {
response.expand = {} response.expand = {}
@@ -175,10 +189,6 @@ export async function trails_show(id: string, loadGPX?: boolean, f: (url: Reques
export async function trails_create(trail: Trail, photos: File[], gpx: File | Blob | null, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) { export async function trails_create(trail: Trail, photos: File[], gpx: File | Blob | null, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) {
if (!pb.authStore.model) {
throw new ClientResponseError({ status: 401, response: { message: "Forbidden" } });
}
for (const waypoint of trail.expand?.waypoints ?? []) { for (const waypoint of trail.expand?.waypoints ?? []) {
const model = await waypoints_create({ const model = await waypoints_create({
...waypoint, ...waypoint,
@@ -199,9 +209,11 @@ export async function trails_create(trail: Trail, photos: File[], gpx: File | Bl
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
let model: Trail = await r.json(); let model: Trail = await r.json();
const formData = new FormData() const formData = new FormData()
@@ -218,11 +230,13 @@ export async function trails_create(trail: Trail, photos: File[], gpx: File | Bl
body: formData, body: formData,
}) })
if (r.ok) { if (!r.ok) {
return await r.json(); const response = await r.json();
} else { throw new APIError(r.status, response.message, response.detail)
throw new ClientResponseError(await r.json())
} }
return await r.json();
} }
export async function trails_update(oldTrail: Trail, newTrail: Trail, photos?: File[], gpx?: File | Blob | null) { export async function trails_update(oldTrail: Trail, newTrail: Trail, photos?: File[], gpx?: File | Blob | null) {
@@ -274,9 +288,11 @@ export async function trails_update(oldTrail: Trail, newTrail: Trail, photos?: F
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
let model: Trail = await r.json(); let model: Trail = await r.json();
const formData = new FormData() const formData = new FormData()
@@ -303,10 +319,12 @@ export async function trails_update(oldTrail: Trail, newTrail: Trail, photos?: F
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
trail.set(model); trail.set(model);
return model; return model;
@@ -329,11 +347,14 @@ export async function trails_delete(trail: Trail) {
method: 'DELETE', method: 'DELETE',
}) })
if (r.ok) { if (!r.ok) {
return await r.json(); const response = await r.json();
} else { throw new APIError(r.status, response.message, response.detail)
throw new ClientResponseError(await r.json())
} }
return await r.json();
} }
export async function trails_get_filter_values(f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch): Promise<TrailFilterValues> { export async function trails_get_filter_values(f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch): Promise<TrailFilterValues> {
@@ -341,23 +362,26 @@ export async function trails_get_filter_values(f: (url: RequestInfo | URL, confi
method: 'GET', method: 'GET',
}) })
if (r.ok) { if (!r.ok) {
return await r.json(); const response = await r.json();
} else { throw new APIError(r.status, response.message, response.detail)
throw new ClientResponseError(await r.json())
} }
return await r.json();
} }
export async function trails_get_bounding_box(f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch): Promise<TrailFilterValues> { export async function trails_get_bounding_box(f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch): Promise<TrailFilterValues> {
const r = await f('/api/v1/trail/bounding-box', { const r = await f('/api/v1/trail/bounding-box', {
method: 'GET', method: 'GET',
}) })
if (!r.ok) {
if (r.ok) { const response = await r.json();
return await r.json(); throw new APIError(r.status, response.message, response.detail)
} else {
throw new ClientResponseError(await r.json())
} }
return await r.json();
} }
export async function trails_upload(file: File, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch): Promise<TrailFilterValues> { export async function trails_upload(file: File, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch): Promise<TrailFilterValues> {
@@ -370,12 +394,13 @@ export async function trails_upload(file: File, f: (url: RequestInfo | URL, conf
method: 'PUT', method: 'PUT',
body: fd body: fd
}) })
if (!r.ok) {
if (r.ok) { const response = await r.json();
return await r.json(); throw new APIError(r.status, response.message, response.detail)
} else {
throw new ClientResponseError(await r.json())
} }
return await r.json();
} }
export async function fetchGPX(trail: { gpx?: string } & Record<string, any>, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) { export async function fetchGPX(trail: { gpx?: string } & Record<string, any>, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) {

View File

@@ -1,6 +1,7 @@
import type { User, UserAnonymous } from "$lib/models/user"; import type { User, UserAnonymous } from "$lib/models/user";
import { pb } from "$lib/pocketbase"; import { pb } from "$lib/pocketbase";
import { ClientResponseError, type AuthMethodsList } from "pocketbase"; import { APIError } from "$lib/util/api_util";
import { type AuthMethodsList } from "pocketbase";
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
export const currentUser: Writable<User | null> = writable<User | null>() export const currentUser: Writable<User | null> = writable<User | null>()
@@ -12,9 +13,11 @@ export async function users_create(user: User) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const createdUser: User = await r.json(); const createdUser: User = await r.json();
return createdUser; return createdUser;
@@ -26,13 +29,14 @@ export async function users_search(q: string, includeSelf: boolean = true) {
}), { }), {
method: 'GET', method: 'GET',
}) })
const response = await r.json() if (!r.ok) {
const response = await r.json();
if (r.ok) { throw new APIError(r.status, response.message, response.detail)
return response.items;
} else {
throw new ClientResponseError(response)
} }
const response = await r.json()
return response.items;
} }
export async function users_show(id: string, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) { export async function users_show(id: string, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) {
@@ -40,12 +44,13 @@ export async function users_show(id: string, f: (url: RequestInfo | URL, config?
method: 'GET', method: 'GET',
}) })
const response: UserAnonymous = await r.json() const response: UserAnonymous = await r.json()
if (!r.ok) {
if (r.ok) { const response = await r.json();
return response; throw new APIError(r.status, response.message, response.detail)
} else {
throw new ClientResponseError(response)
} }
return response;
} }
export async function users_auth_methods(f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch): Promise<AuthMethodsList> { export async function users_auth_methods(f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch): Promise<AuthMethodsList> {
@@ -53,11 +58,12 @@ export async function users_auth_methods(f: (url: RequestInfo | URL, config?: Re
method: 'GET', method: 'GET',
}) })
if (r.ok) { if (!r.ok) {
return await r.json() const response = await r.json();
} else { throw new APIError(r.status, response.message, response.detail)
throw new ClientResponseError(await r.json())
} }
return await r.json()
} }
@@ -68,11 +74,11 @@ export async function login(user: User) {
body: JSON.stringify(user), body: JSON.stringify(user),
}) })
if (r.ok) { if (!r.ok) {
pb.authStore.loadFromCookie(document.cookie) const response = await r.json();
} else { throw new APIError(r.status, response.message, response.detail)
throw new ClientResponseError(await r.json())
} }
pb.authStore.loadFromCookie(document.cookie)
} }
@@ -81,13 +87,13 @@ export async function oauth_login(data: { name: string, code: string, codeVerifi
method: 'POST', method: 'POST',
body: JSON.stringify(data) body: JSON.stringify(data)
}) })
if (!r.ok) {
if (r.ok) { const response = await r.json();
pb.authStore.loadFromCookie(document.cookie) throw new APIError(r.status, response.message, response.detail)
} else {
throw new ClientResponseError(await r.json())
} }
pb.authStore.loadFromCookie(document.cookie)
} }
@@ -102,9 +108,11 @@ export async function users_update(user: User | { [K in keyof User]?: User[K] },
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
if (avatar) { if (avatar) {
const formData = new FormData(); const formData = new FormData();
@@ -117,8 +125,10 @@ export async function users_update(user: User | { [K in keyof User]?: User[K] },
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
} }
const model: User = await r.json(); const model: User = await r.json();
@@ -131,8 +141,10 @@ export async function users_delete(user: User) {
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
} }
export async function users_reset_password(reset: { email: string }) { export async function users_reset_password(reset: { email: string }) {
@@ -140,12 +152,13 @@ export async function users_reset_password(reset: { email: string }) {
method: 'POST', method: 'POST',
body: JSON.stringify(reset), body: JSON.stringify(reset),
}) })
if (!r.ok) {
if (r.ok) { const response = await r.json();
return await r.json(); throw new APIError(r.status, response.message, response.detail)
} else {
throw new ClientResponseError(await r.json())
} }
return await r.json();
} }
export async function users_confirm_reset(reset: { password: string, passwordConfirm: string, token: string }) { export async function users_confirm_reset(reset: { password: string, passwordConfirm: string, token: string }) {
@@ -153,10 +166,11 @@ export async function users_confirm_reset(reset: { password: string, passwordCon
method: 'POST', method: 'POST',
body: JSON.stringify(reset), body: JSON.stringify(reset),
}) })
if (!r.ok) {
const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
}
if (r.ok) {
return await r.json(); return await r.json();
} else {
throw new ClientResponseError(await r.json())
}
} }

View File

@@ -3,8 +3,8 @@ import type Track from "$lib/models/gpx/track";
import TrackSegment from "$lib/models/gpx/track-segment"; import TrackSegment from "$lib/models/gpx/track-segment";
import Waypoint from "$lib/models/gpx/waypoint"; import Waypoint from "$lib/models/gpx/waypoint";
import { type ValhallaAnchor, type ValhallaHeightResponse, type ValhallaRouteResponse } from "$lib/models/valhalla"; import { type ValhallaAnchor, type ValhallaHeightResponse, type ValhallaRouteResponse } from "$lib/models/valhalla";
import { APIError } from "$lib/util/api_util";
import { decodePolyline, encodePolyline } from "$lib/util/polyline_util"; import { decodePolyline, encodePolyline } from "$lib/util/polyline_util";
import { ClientResponseError } from "pocketbase";
const emtpyTrack: Track = { trkseg: [] } const emtpyTrack: Track = { trkseg: [] }
@@ -44,8 +44,10 @@ export async function calculateRouteBetween(startLat: number, startLon: number,
let r = await fetch("/api/v1/valhalla/route", { method: "POST", body: JSON.stringify(requestBody) }) let r = await fetch("/api/v1/valhalla/route", { method: "POST", body: JSON.stringify(requestBody) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const routeResponse: ValhallaRouteResponse = await r.json(); const routeResponse: ValhallaRouteResponse = await r.json();
shape = routeResponse.trip.legs[0].shape shape = routeResponse.trip.legs[0].shape
} else { } else {
@@ -55,8 +57,10 @@ export async function calculateRouteBetween(startLat: number, startLon: number,
const r2 = await fetch("/api/v1/valhalla/height", { method: "POST", body: JSON.stringify({ encoded_polyline: shape }) }) const r2 = await fetch("/api/v1/valhalla/height", { method: "POST", body: JSON.stringify({ encoded_polyline: shape }) })
if (!r2.ok) { if (!r2.ok) {
throw new ClientResponseError(await r2.json()) const response = await r2.json();
throw new APIError(r2.status, response.message, response.detail)
} }
const heightResponse: ValhallaHeightResponse = await r2.json() const heightResponse: ValhallaHeightResponse = await r2.json()
const points = decodePolyline(shape); const points = decodePolyline(shape);
const waypoints = points.map((p, i) => new Waypoint({ $: { lat: p[0], lon: p[1] }, ele: heightResponse.height[i] })) const waypoints = points.map((p, i) => new Waypoint({ $: { lat: p[0], lon: p[1] }, ele: heightResponse.height[i] }))

View File

@@ -1,6 +1,6 @@
import { Waypoint } from "$lib/models/waypoint"; import { Waypoint } from "$lib/models/waypoint";
import { pb } from "$lib/pocketbase"; import { pb } from "$lib/pocketbase";
import { ClientResponseError } from "pocketbase"; import { APIError } from "$lib/util/api_util";
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
export const waypoint: Writable<Waypoint> = writable(new Waypoint(0, 0)); export const waypoint: Writable<Waypoint> = writable(new Waypoint(0, 0));
@@ -15,9 +15,11 @@ export async function waypoints_create(waypoint: Waypoint, f: (url: RequestInfo
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
if (waypoint._photos && waypoint._photos.length) { if (waypoint._photos && waypoint._photos.length) {
let model: Waypoint = await r.json(); let model: Waypoint = await r.json();
@@ -31,13 +33,14 @@ export async function waypoints_create(waypoint: Waypoint, f: (url: RequestInfo
method: 'POST', method: 'POST',
body: formData, body: formData,
}) })
if (!r.ok) {
const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
}
} }
if (r.ok) {
return await r.json(); return await r.json();
} else {
throw new ClientResponseError(await r.json())
}
} }
@@ -50,7 +53,8 @@ export async function waypoints_update(oldWaypoint: Waypoint, newWaypoint: Waypo
}) })
if (!r.ok) { if (!r.ok) {
throw new ClientResponseError(await r.json()) const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
} }
const formData = new FormData() const formData = new FormData()
@@ -69,23 +73,24 @@ export async function waypoints_update(oldWaypoint: Waypoint, newWaypoint: Waypo
method: 'POST', method: 'POST',
body: formData, body: formData,
}) })
if (!r.ok) {
const response = await r.json();
if (r.ok) { throw new APIError(r.status, response.message, response.detail)
return await r.json();
} else {
throw new ClientResponseError(await r.json())
} }
return await r.json();
} }
export async function waypoints_delete(waypoint: Waypoint) { export async function waypoints_delete(waypoint: Waypoint) {
const r = await fetch('/api/v1/waypoint/' + waypoint.id, { const r = await fetch('/api/v1/waypoint/' + waypoint.id, {
method: 'DELETE', method: 'DELETE',
}) })
if (!r.ok) {
const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
}
if (r.ok) {
return await r.json(); return await r.json();
} else {
throw new ClientResponseError(await r.json())
}
} }

View File

@@ -4,6 +4,20 @@ import { pb } from "$lib/pocketbase";
import { ZodError, type ZodSchema } from "zod"; import { ZodError, type ZodSchema } from "zod";
import { RecordListOptionsSchema, RecordIdSchema, RecordOptionsSchema } from "$lib/models/api/base_schema"; import { RecordListOptionsSchema, RecordIdSchema, RecordOptionsSchema } from "$lib/models/api/base_schema";
export class APIError extends Error {
status: number;
message: string;
detail: any;
constructor(status: number, message: string, detail?: any) {
super();
this.status = status;
this.message = message;
this.detail = detail
}
}
export enum Collection { export enum Collection {
users = "users", users = "users",
categories = "categories", categories = "categories",
@@ -108,7 +122,7 @@ export async function remove(event: RequestEvent, collection: Collection) {
export function handleError(e: any) { export function handleError(e: any) {
if (e instanceof ZodError) { if (e instanceof ZodError) {
return error(400, { message: "invalid_params", details: e.issues } as any) return error(400, { message: "invalid_params", detail: e.issues } as any)
} else if (e instanceof ClientResponseError && e.status > 0) { } else if (e instanceof ClientResponseError && e.status > 0) {
return error(e.status as NumericRange<400, 599>, { message: e.message, detail: e.originalError.data } as any) return error(e.status as NumericRange<400, 599>, { message: e.message, detail: e.originalError.data } as any)
} else if (e instanceof SyntaxError) { } else if (e instanceof SyntaxError) {

View File

@@ -1,7 +1,6 @@
import { pb } from "$lib/pocketbase"; import { pb } from "$lib/pocketbase";
import { handleError } from "$lib/util/api_util"; import { handleError } from "$lib/util/api_util";
import { error, json, type RequestEvent } from "@sveltejs/kit"; import { error, json, type RequestEvent } from "@sveltejs/kit";
import { ClientResponseError } from "pocketbase";
import { z } from "zod"; import { z } from "zod";
export async function POST(event: RequestEvent) { export async function POST(event: RequestEvent) {

View File

@@ -1,6 +1,7 @@
import { SummitLog } from "$lib/models/summit_log"; import { SummitLog } from "$lib/models/summit_log";
import type { Trail } from "$lib/models/trail"; import type { Trail } from "$lib/models/trail";
import { trails_create } from "$lib/stores/trail_store"; import { trails_create } from "$lib/stores/trail_store";
import { handleError } from "$lib/util/api_util";
import { fromFile, fromFIT, fromKML, fromTCX, gpx2trail, isFITFile } from "$lib/util/gpx_util"; import { fromFile, fromFIT, fromKML, fromTCX, gpx2trail, isFITFile } from "$lib/util/gpx_util";
import { error, json, type RequestEvent } from "@sveltejs/kit"; import { error, json, type RequestEvent } from "@sveltejs/kit";
import { ClientResponseError } from "pocketbase"; import { ClientResponseError } from "pocketbase";
@@ -35,15 +36,11 @@ export async function PUT(event: RequestEvent) {
try { try {
trail = await trails_create(trail, [], gpxFile, event.fetch); trail = await trails_create(trail, [], gpxFile, event.fetch);
} catch (e: any) { } catch (e: any) {
console.log(e); throw handleError(e)
throw e
} }
return json(trail); return json(trail);
} catch (e: any) { } catch (e: any) {
console.log(e); throw handleError(e)
throw error(e.status, e)
} }
} }

View File

@@ -1,7 +1,8 @@
import type { List, ListFilter } from "$lib/models/list"; import type { List, ListFilter } from "$lib/models/list";
import { lists_index, lists_show } from "$lib/stores/list_store"; import { lists_index, lists_show } from "$lib/stores/list_store";
import { error, type Load } from "@sveltejs/kit"; import { APIError } from "$lib/util/api_util";
import { ClientResponseError, type ListResult } from "pocketbase"; import { error, type Load, type NumericRange } from "@sveltejs/kit";
import { type ListResult } from "pocketbase";
export const load: Load = async ({ params, fetch, url }) => { export const load: Load = async ({ params, fetch, url }) => {
const filter: ListFilter = { const filter: ListFilter = {
@@ -20,9 +21,9 @@ export const load: Load = async ({ params, fetch, url }) => {
lists = { items: [list], page: 1, perPage: 1, totalItems: 1, totalPages: 1 } lists = { items: [list], page: 1, perPage: 1, totalItems: 1, totalPages: 1 }
} catch (e) { } catch (e) {
if (e instanceof ClientResponseError && e.status == 404) { if (e instanceof APIError) {
error(404, { error(e.status as NumericRange<400, 599>, {
message: 'Not found' message: e.status == 404 ? 'Not found' : e.message
}); });
} }
throw e throw e

View File

@@ -1,8 +1,8 @@
import { List } from "$lib/models/list"; import { List } from "$lib/models/list";
import { lists_show } from "$lib/stores/list_store"; import { lists_show } from "$lib/stores/list_store";
import { APIError } from "$lib/util/api_util";
import { getFileURL } from "$lib/util/file_util"; import { getFileURL } from "$lib/util/file_util";
import { error, type Load } from "@sveltejs/kit"; import { error, type Load, type NumericRange } from "@sveltejs/kit";
import { ClientResponseError } from "pocketbase";
export const load: Load = async ({ params, fetch, data }) => { export const load: Load = async ({ params, fetch, data }) => {
if (!params.id) { if (!params.id) {
@@ -21,8 +21,8 @@ export const load: Load = async ({ params, fetch, data }) => {
return { list: list, previewUrl: previewURL } return { list: list, previewUrl: previewURL }
} catch (e) { } catch (e) {
if (e instanceof ClientResponseError) { if (e instanceof APIError) {
throw error(e.status as any, e.message) throw error(e.status as NumericRange<400, 599>, e.message)
} }
throw e throw e
} }

View File

@@ -9,9 +9,10 @@
import { theme } from "$lib/stores/theme_store"; import { theme } from "$lib/stores/theme_store";
import { show_toast } from "$lib/stores/toast_store"; import { show_toast } from "$lib/stores/toast_store";
import { login } from "$lib/stores/user_store"; import { login } from "$lib/stores/user_store";
import { APIError } from "$lib/util/api_util";
import { validator } from "@felte/validator-zod"; import { validator } from "@felte/validator-zod";
import { createForm } from "felte"; import { createForm } from "felte";
import { ClientResponseError, type AuthProviderInfo } from "pocketbase"; import { type AuthProviderInfo } from "pocketbase";
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { z } from "zod"; import { z } from "zod";
@@ -51,7 +52,7 @@
window.location.href = $page.url.searchParams.get("r") ?? "/"; window.location.href = $page.url.searchParams.get("r") ?? "/";
} catch (e) { } catch (e) {
if ( if (
e instanceof ClientResponseError && e instanceof APIError &&
e.message == "Failed to authenticate." e.message == "Failed to authenticate."
) { ) {
show_toast({ show_toast({

View File

@@ -1,15 +1,14 @@
import { lists_index } from "$lib/stores/list_store";
import { trails_show } from "$lib/stores/trail_store"; import { trails_show } from "$lib/stores/trail_store";
import { error, type ServerLoad } from "@sveltejs/kit"; import { APIError } from "$lib/util/api_util";
import { ClientResponseError } from "pocketbase"; import { error, type NumericRange, type ServerLoad } from "@sveltejs/kit";
export const load: ServerLoad = async ({ params, locals, fetch }) => { export const load: ServerLoad = async ({ params, locals, fetch }) => {
try { try {
await trails_show(params.id!, true, fetch) await trails_show(params.id!, true, fetch)
} catch (e) { } catch (e) {
if (e instanceof ClientResponseError && e.status == 404) { if (e instanceof APIError) {
error(404, { error(e.status as NumericRange<400, 599>, {
message: 'Not found' message: e.status == 404 ? 'Not found' : e.message
}); });
} }

View File

@@ -1,14 +1,14 @@
import { trails_show } from "$lib/stores/trail_store"; import { trails_show } from "$lib/stores/trail_store";
import { error, type Load } from "@sveltejs/kit"; import { APIError } from "$lib/util/api_util";
import { ClientResponseError } from "pocketbase"; import { error, type Load, type NumericRange } from "@sveltejs/kit";
export const load: Load = async ({ params, fetch }) => { export const load: Load = async ({ params, fetch }) => {
try { try {
await trails_show(params.id!, true, fetch) await trails_show(params.id!, true, fetch)
} catch (e) { } catch (e) {
if (e instanceof ClientResponseError && e.status == 404) { if (e instanceof APIError) {
error(404, { error(e.status as NumericRange<400, 599>, {
message: 'Not found' message: e.status == 404 ? 'Not found' : e.message
}); });
} }
console.log(e); console.log(e);

View File

@@ -1,7 +1,7 @@
import { follows_a_b, follows_counts } from "$lib/stores/follow_store"; import { follows_a_b, follows_counts } from "$lib/stores/follow_store";
import { users_show } from "$lib/stores/user_store"; import { users_show } from "$lib/stores/user_store";
import { error, type ServerLoad } from "@sveltejs/kit"; import { APIError } from "$lib/util/api_util";
import { ClientResponseError } from "pocketbase"; import { error, type NumericRange, type ServerLoad } from "@sveltejs/kit";
export const load: ServerLoad = async ({ params, locals, fetch }) => { export const load: ServerLoad = async ({ params, locals, fetch }) => {
@@ -23,9 +23,9 @@ export const load: ServerLoad = async ({ params, locals, fetch }) => {
return { user, isOwnProfile, ...followCounts, follow: follow } return { user, isOwnProfile, ...followCounts, follow: follow }
} catch (e) { } catch (e) {
if (e instanceof ClientResponseError && e.status == 404) { if (e instanceof APIError) {
error(404, { error(e.status as NumericRange<400, 599>, {
message: 'Not found' message: e.status == 404 ? 'Not found' : e.message
}); });
} else { } else {
throw e throw e

View File

@@ -1,8 +1,6 @@
import { pb } from "$lib/pocketbase";
import { lists_index } from "$lib/stores/list_store";
import { trails_show } from "$lib/stores/trail_store"; import { trails_show } from "$lib/stores/trail_store";
import { APIError } from "$lib/util/api_util";
import { error, type Load } from "@sveltejs/kit"; import { error, type Load } from "@sveltejs/kit";
import { ClientResponseError } from "pocketbase";
export const load: Load = async ({ params, fetch }) => { export const load: Load = async ({ params, fetch }) => {
try { try {
@@ -10,7 +8,7 @@ export const load: Load = async ({ params, fetch }) => {
return { trail } return { trail }
} catch (e) { } catch (e) {
if (e instanceof ClientResponseError && e.status == 404) { if (e instanceof APIError && e.status == 404) {
error(404, { error(404, {
message: 'Not found' message: 'Not found'
}); });