chore: commit pending ZXDB explorer changes prior to index perf work
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
This commit is contained in:
@@ -22,7 +22,11 @@ export async function GET(_req: NextRequest, ctx: { params: Promise<{ id: string
|
||||
});
|
||||
}
|
||||
return new Response(JSON.stringify(detail), {
|
||||
headers: { "content-type": "application/json", "cache-control": "no-store" },
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
// Cache for 1h on CDN, allow stale while revalidating for a day
|
||||
"cache-control": "public, max-age=0, s-maxage=3600, stale-while-revalidate=86400",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,9 @@ const querySchema = z.object({
|
||||
pageSize: z.coerce.number().int().positive().max(100).optional(),
|
||||
});
|
||||
|
||||
export async function GET(req: NextRequest, ctx: { params: { id: string } }) {
|
||||
const p = paramsSchema.safeParse(ctx.params);
|
||||
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 });
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@ import { listGenres } from "@/server/repo/zxdb";
|
||||
export async function GET() {
|
||||
const data = await listGenres();
|
||||
return new Response(JSON.stringify({ items: data }), {
|
||||
headers: { "content-type": "application/json", "cache-control": "no-store" },
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"cache-control": "public, max-age=0, s-maxage=3600, stale-while-revalidate=86400",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,9 @@ const querySchema = z.object({
|
||||
pageSize: z.coerce.number().int().positive().max(100).optional(),
|
||||
});
|
||||
|
||||
export async function GET(req: NextRequest, ctx: { params: { id: string } }) {
|
||||
const p = paramsSchema.safeParse(ctx.params);
|
||||
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,
|
||||
|
||||
@@ -8,8 +8,9 @@ const querySchema = z.object({
|
||||
pageSize: z.coerce.number().int().positive().max(100).optional(),
|
||||
});
|
||||
|
||||
export async function GET(req: NextRequest, ctx: { params: { id: string } }) {
|
||||
const p = paramsSchema.safeParse(ctx.params);
|
||||
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 });
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@ import { listLanguages } from "@/server/repo/zxdb";
|
||||
export async function GET() {
|
||||
const data = await listLanguages();
|
||||
return new Response(JSON.stringify({ items: data }), {
|
||||
headers: { "content-type": "application/json", "cache-control": "no-store" },
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"cache-control": "public, max-age=0, s-maxage=3600, stale-while-revalidate=86400",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,9 @@ const querySchema = z.object({
|
||||
pageSize: z.coerce.number().int().positive().max(100).optional(),
|
||||
});
|
||||
|
||||
export async function GET(req: NextRequest, ctx: { params: { id: string } }) {
|
||||
const p = paramsSchema.safeParse(ctx.params);
|
||||
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 });
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@ import { listMachinetypes } from "@/server/repo/zxdb";
|
||||
export async function GET() {
|
||||
const data = await listMachinetypes();
|
||||
return new Response(JSON.stringify({ items: data }), {
|
||||
headers: { "content-type": "application/json", "cache-control": "no-store" },
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"cache-control": "public, max-age=0, s-maxage=3600, stale-while-revalidate=86400",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { NextRequest } from "next/server";
|
||||
import { z } from "zod";
|
||||
import { searchEntries } from "@/server/repo/zxdb";
|
||||
import { searchEntries, getEntryFacets } from "@/server/repo/zxdb";
|
||||
|
||||
const querySchema = z.object({
|
||||
q: z.string().optional(),
|
||||
@@ -14,6 +14,7 @@ const querySchema = z.object({
|
||||
.optional(),
|
||||
machinetypeId: z.coerce.number().int().positive().optional(),
|
||||
sort: z.enum(["title", "id_desc"]).optional(),
|
||||
facets: z.coerce.boolean().optional(),
|
||||
});
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
@@ -26,6 +27,7 @@ export async function GET(req: NextRequest) {
|
||||
languageId: searchParams.get("languageId") ?? undefined,
|
||||
machinetypeId: searchParams.get("machinetypeId") ?? undefined,
|
||||
sort: searchParams.get("sort") ?? undefined,
|
||||
facets: searchParams.get("facets") ?? undefined,
|
||||
});
|
||||
if (!parsed.success) {
|
||||
return new Response(
|
||||
@@ -34,7 +36,10 @@ export async function GET(req: NextRequest) {
|
||||
);
|
||||
}
|
||||
const data = await searchEntries(parsed.data);
|
||||
return new Response(JSON.stringify(data), {
|
||||
const body = parsed.data.facets
|
||||
? { ...data, facets: await getEntryFacets(parsed.data) }
|
||||
: data;
|
||||
return new Response(JSON.stringify(body), {
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user