This commit is contained in:
Stefan ATZLESBERGER
2026-04-16 12:55:18 +02:00
parent 97dc4d043a
commit dfbcd20ab6
14 changed files with 723 additions and 116 deletions
+95 -20
View File
@@ -1,39 +1,114 @@
import { serve } from "bun";
import index from "./index.html";
import { getDb } from "./server/db";
import { createSnippet, deleteSnippet, getSnippetById, listSnippets, updateSnippet } from "./server/snippets";
getDb();
async function readJson(req: Request): Promise<unknown> {
try {
return await req.json();
} catch {
return null;
}
}
const server = serve({
routes: {
// Serve index.html for all unmatched routes.
"/*": index,
"/api/hello": {
"/api/snippets": {
async GET(req) {
return Response.json({
message: "Hello, world!",
method: "GET",
});
const url = new URL(req.url);
const q = url.searchParams.get("q");
const sort = url.searchParams.get("sort");
return Response.json(listSnippets(q, sort));
},
async PUT(req) {
return Response.json({
message: "Hello, world!",
method: "PUT",
async POST(req) {
const body = await readJson(req);
if (!body || typeof body !== "object") {
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
}
const o = body as Record<string, unknown>;
const tags = Array.isArray(o.tags)
? o.tags.filter((t): t is string => typeof t === "string")
: [];
const snippet = createSnippet({
title:
o.title === null
? null
: typeof o.title === "string"
? o.title
: undefined,
body: typeof o.body === "string" ? o.body : "",
tags,
});
return Response.json(snippet, { status: 201 });
},
},
"/api/hello/:name": async req => {
const name = req.params.name;
return Response.json({
message: `Hello, ${name}!`,
});
"/api/snippets/:id": {
async GET(req) {
const id = Number(req.params.id);
if (!Number.isFinite(id)) {
return Response.json({ error: "Invalid id" }, { status: 400 });
}
const snippet = getSnippetById(id);
if (!snippet) {
return Response.json({ error: "Not found" }, { status: 404 });
}
return Response.json(snippet);
},
async PATCH(req) {
const id = Number(req.params.id);
if (!Number.isFinite(id)) {
return Response.json({ error: "Invalid id" }, { status: 400 });
}
const body = await readJson(req);
if (!body || typeof body !== "object") {
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
}
const o = body as Record<string, unknown>;
const patch: {
title?: string | null;
body?: string;
tags?: string[];
sort_order?: number;
} = {};
if ("title" in o) {
patch.title = o.title === null ? null : String(o.title);
}
if ("body" in o && typeof o.body === "string") {
patch.body = o.body;
}
if ("tags" in o && Array.isArray(o.tags)) {
patch.tags = o.tags.filter((t): t is string => typeof t === "string");
}
if ("sort_order" in o && typeof o.sort_order === "number" && Number.isFinite(o.sort_order)) {
patch.sort_order = o.sort_order;
}
const snippet = updateSnippet(id, patch);
if (!snippet) {
return Response.json({ error: "Not found" }, { status: 404 });
}
return Response.json(snippet);
},
async DELETE(req) {
const id = Number(req.params.id);
if (!Number.isFinite(id)) {
return Response.json({ error: "Invalid id" }, { status: 400 });
}
const ok = deleteSnippet(id);
if (!ok) {
return Response.json({ error: "Not found" }, { status: 404 });
}
return new Response(null, { status: 204 });
},
},
"/*": index,
},
development: process.env.NODE_ENV !== "production" && {
// Enable browser hot reloading in development
hmr: true,
// Echo console logs from the browser to the server
console: true,
},
});