snapshot
This commit is contained in:
+4
-206
@@ -1,217 +1,15 @@
|
||||
import { serve } from "bun";
|
||||
import index from "./index.html";
|
||||
import { getDb } from "./server/db";
|
||||
import { createSnippet, deleteSnippet, getSnippetById, listSnippets, updateSnippet } from "./server/snippets";
|
||||
import {
|
||||
createTagTreeNode,
|
||||
deleteTagTreeNode,
|
||||
listTagTreeNodes,
|
||||
suggestTagTreeItems,
|
||||
updateTagTreeNode,
|
||||
} from "./server/tagTree";
|
||||
import { snippetRoutes } from "./server/routes/snippetsHandlers";
|
||||
import { tagTreeRoutes } from "./server/routes/tagTreeHandlers";
|
||||
|
||||
getDb();
|
||||
|
||||
async function readJson(req: Request): Promise<unknown> {
|
||||
try {
|
||||
return await req.json();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const server = serve({
|
||||
routes: {
|
||||
"/api/snippets": {
|
||||
async GET(req) {
|
||||
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 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/tag-suggestions": {
|
||||
async GET(req) {
|
||||
const url = new URL(req.url);
|
||||
const q = url.searchParams.get("q") ?? "";
|
||||
const database = getDb();
|
||||
return Response.json({ items: suggestTagTreeItems(database, q) });
|
||||
},
|
||||
},
|
||||
|
||||
"/api/tag-tree": {
|
||||
async GET() {
|
||||
return Response.json(listTagTreeNodes());
|
||||
},
|
||||
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>;
|
||||
try {
|
||||
const node = createTagTreeNode({
|
||||
name: typeof o.name === "string" ? o.name : "",
|
||||
parent_id:
|
||||
o.parent_id === null || o.parent_id === undefined
|
||||
? null
|
||||
: typeof o.parent_id === "number"
|
||||
? o.parent_id
|
||||
: Number(o.parent_id),
|
||||
color: o.color === null || o.color === undefined ? null : String(o.color),
|
||||
label_prefix:
|
||||
o.label_prefix === null || o.label_prefix === undefined
|
||||
? null
|
||||
: typeof o.label_prefix === "string"
|
||||
? o.label_prefix
|
||||
: String(o.label_prefix),
|
||||
});
|
||||
return Response.json(node, { status: 201 });
|
||||
} catch (e) {
|
||||
const msg = e instanceof Error ? e.message : "Fehler";
|
||||
return Response.json({ error: msg }, { status: 400 });
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
"/api/tag-tree/:id": {
|
||||
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: {
|
||||
name?: string;
|
||||
parent_id?: number | null;
|
||||
color?: string | null;
|
||||
label_prefix?: string | null;
|
||||
} = {};
|
||||
if ("name" in o && typeof o.name === "string") patch.name = o.name;
|
||||
if ("parent_id" in o) {
|
||||
patch.parent_id =
|
||||
o.parent_id === null ? null : typeof o.parent_id === "number" ? o.parent_id : Number(o.parent_id);
|
||||
}
|
||||
if ("color" in o) {
|
||||
patch.color = o.color === null || o.color === undefined ? null : String(o.color);
|
||||
}
|
||||
if ("label_prefix" in o) {
|
||||
patch.label_prefix =
|
||||
o.label_prefix === null || o.label_prefix === undefined
|
||||
? null
|
||||
: typeof o.label_prefix === "string"
|
||||
? o.label_prefix
|
||||
: String(o.label_prefix);
|
||||
}
|
||||
try {
|
||||
const node = updateTagTreeNode(id, patch);
|
||||
if (!node) {
|
||||
return Response.json({ error: "Not found" }, { status: 404 });
|
||||
}
|
||||
return Response.json(node);
|
||||
} catch (e) {
|
||||
const msg = e instanceof Error ? e.message : "Fehler";
|
||||
return Response.json({ error: msg }, { status: 400 });
|
||||
}
|
||||
},
|
||||
async DELETE(req) {
|
||||
const id = Number(req.params.id);
|
||||
if (!Number.isFinite(id)) {
|
||||
return Response.json({ error: "Invalid id" }, { status: 400 });
|
||||
}
|
||||
const ok = deleteTagTreeNode(id);
|
||||
if (!ok) {
|
||||
return Response.json({ error: "Not found" }, { status: 404 });
|
||||
}
|
||||
return new Response(null, { status: 204 });
|
||||
},
|
||||
},
|
||||
|
||||
"/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 });
|
||||
},
|
||||
},
|
||||
|
||||
...snippetRoutes,
|
||||
...tagTreeRoutes,
|
||||
"/*": index,
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user