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 <noreply@anthropic.com>
This commit is contained in:
1 parent
7b0a6738dd
commit
6963e297b0
19 files changed
+1599
No files matched your search
@@ -0,0 +1,58 @@
|
||||
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();
|
||||
},
|
||||
}),
|
||||
];
|
||||
Reference in new issue
Block a user