Files
STTracker/apps/server/src/routes/copies.ts
T
Lucas WintherandClaude Opus 5.5 6963e297b0 feat(server): REST API, auth, sources, changes, export
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]>
2026-10-30 21:15:01 +01:00

59 lines
1.8 KiB
TypeScript

import { createCopy, listCopies, softDeleteCopy, updateCopy } from "@sttracker/core/copies";
import { z } from "zod";
import { json, noContent, route } from "../http.ts";
import { customFields, partialDate, text } from "./schemas.ts";
const copyPatch = z
.object({
workId: z.string().min(1).nullable(),
titleHint: z.string().max(1000).nullable(),
format: z.string().max(200).nullable(),
acquiredFrom: z.string().max(500).nullable(),
acquiredAt: partialDate.nullable(),
priceCents: z.number().int().nullable(),
currency: z.string().length(3).nullable(),
notes: text().nullable(),
customFields,
sourceRef: z.string().max(500).nullable(),
})
.partial()
.strict();
type CopyArg = Parameters<typeof updateCopy>[3];
export const copyRoutes = [
route({
method: "GET",
path: "copies",
summary: "Your owned copies (optionally of one work).",
auth: "any:read",
query: z.object({ workId: z.string().optional() }),
handler: async ({ deps, user, query }) => listCopies(deps.db, user.id, query),
}),
route({
method: "POST",
path: "copies",
summary: "Record an owned copy.",
auth: "any:write",
body: copyPatch,
handler: async ({ deps, user, body }) => json(await createCopy(deps.db, user.id, body as CopyArg), 201),
}),
route({
method: "PATCH",
path: "copies/:id",
summary: "Edit an owned copy.",
auth: "any:write",
body: copyPatch,
handler: async ({ deps, user, params, body }) => updateCopy(deps.db, user.id, params.id!, body as CopyArg),
}),
route({
method: "DELETE",
path: "copies/:id",
summary: "Soft-delete an owned copy.",
auth: "any:write",
handler: async ({ deps, user, params }) => {
await softDeleteCopy(deps.db, user.id, params.id!);
return noContent();
},
}),
];