Files
wanderer/web/src/lib/util/api_util.ts
2025-08-20 16:51:33 +02:00

166 lines
5.5 KiB
TypeScript

import { error, json, type NumericRange, type RequestEvent } from "@sveltejs/kit";
import { ClientResponseError, type ListResult } from "pocketbase";
import { ZodError, type ZodSchema } from "zod";
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 {
users = "users",
activitypub_activities = "activitypub_activities",
activitypub_actors = "activitypub_actors",
categories = "categories",
comments = "comments",
feed = "feed",
follows = "follows",
integrations = "integrations",
list_share = "list_share",
lists = "lists",
notifications = "notifications",
profile_feed = "profile_feed",
settings = "settings",
summit_logs = "summit_logs",
trail_like = "trail_like",
trail_share = "trail_share",
trail_link_share = "trail_link_share",
trails = "trails",
tags = "tags",
waypoints = "waypoints",
trails_bounding_box = "trails_bounding_box",
trails_filter = "trails_filter",
users_anonymous = "users_anonymous",
}
export async function list<T>(event: RequestEvent, collection: Collection) {
const searchParams = Object.fromEntries(event.url.searchParams);
const safeSearchParams = RecordListOptionsSchema.parse(searchParams);
let r: ListResult<T>;
if ((safeSearchParams.perPage ?? 0) < 0) {
const activities: T[] = await event.locals.pb.collection(Collection[collection])
.getFullList<T>(safeSearchParams)
r = {
items: activities,
perPage: -1,
page: 1,
totalItems: activities.length,
totalPages: 1
}
} else {
r = await event.locals.pb.collection(Collection[collection])
.getList<T>(safeSearchParams.page, safeSearchParams.perPage, { ...safeSearchParams })
}
return r
}
export async function show<T>(event: RequestEvent, collection: Collection) {
const params = event.params
const safeParams = RecordIdSchema.parse(params);
const searchParams = Object.fromEntries(event.url.searchParams);
const safeSearchParams = RecordOptionsSchema.parse(searchParams);
const r = await event.locals.pb.collection(collection.toString())
.getOne<T>(safeParams.id, safeSearchParams)
return r
}
export async function create<T>(event: RequestEvent, schema: ZodSchema, collection: Collection) {
const searchParams = Object.fromEntries(event.url.searchParams);
const safeSearchParams = RecordOptionsSchema.parse(searchParams);
const data = await event.request.json();
const safeData = schema.parse(data);
const r = await event.locals.pb.collection(Collection[collection]).create<T>(safeData, { ...safeSearchParams, requestKey: null })
return r
}
export async function update<T>(event: RequestEvent, schema: ZodSchema, collection: Collection) {
const params = event.params
const safeParams = RecordIdSchema.parse(params);
const searchParams = Object.fromEntries(event.url.searchParams);
const safeSearchParams = RecordOptionsSchema.parse(searchParams);
const data = await event.request.json();
const safeData = schema.parse(data);
const r = await event.locals.pb.collection(Collection[collection]).update<T>(safeParams.id, safeData, safeSearchParams)
return r
}
export async function uploadCreate<T>(event: RequestEvent, collection: Collection) {
const searchParams = Object.fromEntries(event.url.searchParams);
const safeSearchParams = RecordOptionsSchema.parse(searchParams);
const data = await event.request.formData();
const r = await event.locals.pb.collection(Collection[collection]).create<T>(data, safeSearchParams)
return r
}
export async function uploadUpdate<T>(event: RequestEvent, collection: Collection) {
const searchParams = Object.fromEntries(event.url.searchParams);
const safeSearchParams = RecordOptionsSchema.parse(searchParams);
const data = await event.request.formData();
if (!data.has('id')) {
throw new Error("data has no id")
}
const r = await event.locals.pb.collection(Collection[collection]).update<T>(data.get('id')!.toString(), data, safeSearchParams)
return r
}
export async function upload<T>(event: RequestEvent, collection: Collection) {
const params = event.params
const safeParams = RecordIdSchema.parse(params);
const data = await event.request.formData();
const r = await event.locals.pb.collection(Collection[collection]).update<T>(safeParams.id, data)
return r
}
export async function remove(event: RequestEvent, collection: Collection) {
const params = event.params
const safeParams = RecordIdSchema.parse(params);
const r = await event.locals.pb.collection(Collection[collection]).delete(safeParams.id)
return { 'acknowledged': r }
}
export function handleError(e: any) {
if (e instanceof ZodError) {
return json({ message: "invalid_params", detail: e.issues }, { status: 400 })
} else if (e instanceof ClientResponseError && e.status > 0) {
return json({ ...e.response, message: e.message, detail: e.originalError.data }, { status: e.status })
} else if (e instanceof SyntaxError) {
return json({ message: "invalid_json" }, { status: 400 })
} else {
return json({ message: e }, { status: 500 })
}
}