Context - Housekeeping commit to capture all current ZXDB Explorer work before index-page performance optimizations. Includes - Server-rendered entry detail page with ISR and parallelized DB queries. - Node runtime for ZXDB API routes and params validation updates for Next 15. - ZXDB repository extensions (facets, label queries, category queries). - Cross-linking and Link-based prefetch across ZXDB UI. - Cache headers on low-churn list APIs. Notes - Follow-up commit will focus specifically on speeding up index pages via SSR initial data and ISR. Signed-off-by: Junie@lucy.xalior.com
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
import { NextRequest } from "next/server";
|
|
import { z } from "zod";
|
|
import { getLabelById, getLabelAuthoredEntries, getLabelPublishedEntries } from "@/server/repo/zxdb";
|
|
|
|
const paramsSchema = z.object({ id: z.coerce.number().int().positive() });
|
|
const querySchema = z.object({
|
|
page: z.coerce.number().int().positive().optional(),
|
|
pageSize: z.coerce.number().int().positive().max(100).optional(),
|
|
});
|
|
|
|
export async function GET(req: NextRequest, ctx: { params: Promise<{ id: string }> }) {
|
|
const raw = await ctx.params;
|
|
const p = paramsSchema.safeParse(raw);
|
|
if (!p.success) {
|
|
return new Response(JSON.stringify({ error: p.error.flatten() }), {
|
|
status: 400,
|
|
headers: { "content-type": "application/json" },
|
|
});
|
|
}
|
|
const { searchParams } = new URL(req.url);
|
|
const q = querySchema.safeParse({
|
|
page: searchParams.get("page") ?? undefined,
|
|
pageSize: searchParams.get("pageSize") ?? undefined,
|
|
});
|
|
if (!q.success) {
|
|
return new Response(JSON.stringify({ error: q.error.flatten() }), {
|
|
status: 400,
|
|
headers: { "content-type": "application/json" },
|
|
});
|
|
}
|
|
const id = p.data.id;
|
|
const label = await getLabelById(id);
|
|
if (!label) {
|
|
return new Response(JSON.stringify({ error: "Not found" }), {
|
|
status: 404,
|
|
headers: { "content-type": "application/json" },
|
|
});
|
|
}
|
|
const page = q.data.page ?? 1;
|
|
const pageSize = q.data.pageSize ?? 20;
|
|
const [authored, published] = await Promise.all([
|
|
getLabelAuthoredEntries(id, { page, pageSize }),
|
|
getLabelPublishedEntries(id, { page, pageSize }),
|
|
]);
|
|
return new Response(
|
|
JSON.stringify({ label, authored, published }),
|
|
{ headers: { "content-type": "application/json", "cache-control": "no-store" } }
|
|
);
|
|
}
|
|
|
|
export const runtime = "nodejs";
|