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]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
7b0a6738dd
commit
6963e297b0
@@ -0,0 +1,49 @@
|
||||
import { apiHandler, errorResponse, type AppDeps, type RouteDef } from "./http.ts";
|
||||
import { attachmentRoutes } from "./routes/attachments.ts";
|
||||
import { authRoutes } from "./routes/auth.ts";
|
||||
import { changeRoutes } from "./routes/changes.ts";
|
||||
import { copyRoutes } from "./routes/copies.ts";
|
||||
import { customFieldRoutes } from "./routes/custom-fields.ts";
|
||||
import { engagementRoutes } from "./routes/engagements.ts";
|
||||
import { entryRoutes } from "./routes/entries.ts";
|
||||
import { exportRoutes } from "./routes/export.ts";
|
||||
import { listRoutes } from "./routes/lists.ts";
|
||||
import { metaRoutes } from "./routes/meta.ts";
|
||||
import { sourceRoutes } from "./routes/sources.ts";
|
||||
import { workRoutes } from "./routes/works.ts";
|
||||
|
||||
export interface App {
|
||||
/** Handle `/api/v1/*` and `/ingest/*`. Anything else is a JSON 404 (the web app is served by `Bun.serve` routes). */
|
||||
fetch(req: Request, server?: { requestIP(req: Request): { address: string } | null }): Promise<Response>;
|
||||
routes: RouteDef[];
|
||||
}
|
||||
|
||||
/** The HTTP API, testable without a listening socket. */
|
||||
export function createApp(deps: AppDeps): App {
|
||||
const routes: RouteDef[] = [
|
||||
...authRoutes,
|
||||
...entryRoutes,
|
||||
...engagementRoutes,
|
||||
...workRoutes,
|
||||
...listRoutes,
|
||||
...copyRoutes,
|
||||
...customFieldRoutes,
|
||||
...attachmentRoutes,
|
||||
...sourceRoutes,
|
||||
...changeRoutes,
|
||||
...exportRoutes,
|
||||
];
|
||||
routes.push(...metaRoutes(() => routes));
|
||||
const api = apiHandler(routes, deps);
|
||||
|
||||
return {
|
||||
routes,
|
||||
async fetch(req, server) {
|
||||
const { pathname } = new URL(req.url);
|
||||
if (pathname.startsWith("/api/v1/")) return api(req, server?.requestIP(req)?.address ?? "unknown");
|
||||
// Phase 1: the ingest mount exists but no plugin has the `ingest` capability.
|
||||
if (pathname.startsWith("/ingest/")) return errorResponse(404, "not_found", "No ingest endpoint for this plugin.");
|
||||
return errorResponse(404, "not_found", "No such endpoint.");
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user