import { json } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; import { requireAuth } from '$lib/server/middleware/authenticate.js'; import * as appService from '$lib/server/services/appService.js'; import { success, error } from '$lib/server/utils/response.js'; import { z } from 'zod'; const quickAddSchema = z.object({ url: z .string() .url('Invalid URL') .refine( (u) => u.startsWith('http://') || u.startsWith('https://'), 'URL must use http or https protocol' ), name: z.string().min(1, 'Name is required').max(200), description: z.string().max(1000).optional() }); /** * POST /api/apps/quick-add — Quick-add an app with sensible defaults. * Accepts { url, name, description? }, creates app with healthcheck enabled * and attempts to auto-detect a favicon icon from the URL's domain. */ export const POST: RequestHandler = async (event) => { const user = requireAuth(event); let body: unknown; try { body = await event.request.json(); } catch { return json(error('Invalid JSON body'), { status: 400 }); } const parsed = quickAddSchema.safeParse(body); if (!parsed.success) { const messages = parsed.error.errors.map((e) => e.message).join(', '); return json(error(messages), { status: 400 }); } const { url, name, description } = parsed.data; // Attempt to derive a favicon URL from the domain let faviconUrl: string | undefined; try { const parsedUrl = new URL(url); faviconUrl = `${parsedUrl.origin}/favicon.ico`; } catch { // URL parsing failed — skip icon detection } try { const app = await appService.create({ name, url, description, icon: faviconUrl, iconType: faviconUrl ? 'url' : 'lucide', healthcheckEnabled: true, healthcheckInterval: 300, healthcheckMethod: 'GET', healthcheckExpectedStatus: 200, healthcheckTimeout: 5000, createdById: user.id }); return json(success(app), { status: 201 }); } catch (err) { const message = err instanceof Error ? err.message : 'Failed to create app'; return json(error(message), { status: 500 }); } };