createApp() serves /api/v1 from a typed route table (zod bodies and queries), with session-cookie and Bearer app-token auth, a CSRF header for cookie writes, login/register rate limiting, body caps, JSON error mapping, OpenAPI generation and a 404 /ingest mount. Co-Authored-By: Claude Opus 5.5 <[email protected]>
57 lines
2.0 KiB
TypeScript
57 lines
2.0 KiB
TypeScript
import { acceptSuggestion, listSuggestions, rejectSuggestion, resolveVisibleWork } from "@sttracker/core/entries";
|
|
import { NotFoundError } from "@sttracker/core/errors";
|
|
import { getWork, searchWorks } from "@sttracker/core/works";
|
|
import { z } from "zod";
|
|
import { noContent, route } from "../http.ts";
|
|
import { mediaType, qInt } from "./schemas.ts";
|
|
|
|
export const workRoutes = [
|
|
route({
|
|
method: "GET",
|
|
path: "works/search",
|
|
summary: "Search works visible to you by title.",
|
|
auth: "any:read",
|
|
query: z.object({ q: z.string().min(1).max(500), mediaType: mediaType.optional(), limit: qInt.optional() }),
|
|
handler: async ({ deps, user, query }) => searchWorks(deps.db, user.id, query.q, { mediaType: query.mediaType, limit: query.limit }),
|
|
}),
|
|
route({
|
|
method: "GET",
|
|
path: "works/:id",
|
|
summary: "One work (follows merges and your aliases).",
|
|
auth: "any:read",
|
|
handler: async ({ deps, user, params }) => {
|
|
const visible = await resolveVisibleWork(deps.db.k, user.id, params.id!);
|
|
const work = await getWork(deps.db, visible.id);
|
|
if (!work) throw new NotFoundError("work");
|
|
return work;
|
|
},
|
|
}),
|
|
route({
|
|
method: "GET",
|
|
path: "works/:id/suggestions",
|
|
summary: "Pending match suggestions for a work.",
|
|
auth: "any:read",
|
|
handler: async ({ deps, user, params }) => listSuggestions(deps.db, user.id, params.id!),
|
|
}),
|
|
route({
|
|
method: "POST",
|
|
path: "suggestions/:id/accept",
|
|
summary: "Accept a match suggestion (moves your entry to the candidate work).",
|
|
auth: "any:write",
|
|
handler: async ({ deps, user, params }) => {
|
|
await acceptSuggestion(deps.db, user.id, params.id!);
|
|
return noContent();
|
|
},
|
|
}),
|
|
route({
|
|
method: "POST",
|
|
path: "suggestions/:id/reject",
|
|
summary: "Reject a match suggestion.",
|
|
auth: "any:write",
|
|
handler: async ({ deps, user, params }) => {
|
|
await rejectSuggestion(deps.db, user.id, params.id!);
|
|
return noContent();
|
|
},
|
|
}),
|
|
];
|