- Fix missing await in pets API route causing empty responses - Fix updateSetting to use upsert pattern instead of update-only - Create missing /api/admin/sounds/upload route (upload was broken) - Wire bulk delete actions in catalog table - Replace native confirm() with useConfirmDialog() across rooms and clone pages - Add error logging to silent catch blocks in radio actions and audit route - Add graceful degradation to devops health endpoint - Add cache eviction to clone icon route to prevent memory leak - Internationalize hardcoded Italian strings to English - Remove placeholder created_at fields from prefix API responses - Remove dead code and fix type errors in translations and import pages - Standardize PERMS import path in analytics export route
83 lines
1.9 KiB
TypeScript
83 lines
1.9 KiB
TypeScript
import { withAdmin } from "@/lib/api-handler";
|
|
import { logger } from "@/lib/logger";
|
|
import { PERMS } from "@/lib/permissions";
|
|
import { runCatalogAudit } from "@/lib/services/catalog-audit";
|
|
|
|
function sseEvent(data: unknown): string {
|
|
return `data: ${JSON.stringify(data)}\n\n`;
|
|
}
|
|
|
|
export const POST = withAdmin(
|
|
{ permission: PERMS.ASSETS_IMPORT },
|
|
async (request) => {
|
|
const encoder = new TextEncoder();
|
|
|
|
let repair = false;
|
|
let repairNitros = false;
|
|
let sql = false;
|
|
let applySql = false;
|
|
let repairFurniData = false;
|
|
let repairStructure = false;
|
|
try {
|
|
const body = (await request.json().catch(() => ({}))) as {
|
|
repair?: unknown;
|
|
repairNitros?: unknown;
|
|
sql?: unknown;
|
|
applySql?: unknown;
|
|
repairFurniData?: unknown;
|
|
repairStructure?: unknown;
|
|
};
|
|
repair = body.repair === true;
|
|
repairNitros = body.repairNitros === true;
|
|
sql = body.sql === true;
|
|
applySql = body.applySql === true;
|
|
repairFurniData = body.repairFurniData === true;
|
|
repairStructure = body.repairStructure === true;
|
|
} catch (err) {
|
|
logger.warn("Failed to parse audit request body", { err });
|
|
}
|
|
|
|
const stream = new ReadableStream({
|
|
async start(controller) {
|
|
const send = (data: unknown) => {
|
|
try {
|
|
controller.enqueue(encoder.encode(sseEvent(data)));
|
|
} catch {
|
|
/* stream closed */
|
|
}
|
|
};
|
|
|
|
try {
|
|
await runCatalogAudit(send, {
|
|
repair,
|
|
repairNitros,
|
|
sql,
|
|
applySql,
|
|
repairFurniData,
|
|
repairStructure,
|
|
});
|
|
} catch (err) {
|
|
send({
|
|
type: "error",
|
|
message: `Audit threw: ${(err as Error).message}`,
|
|
});
|
|
}
|
|
|
|
try {
|
|
controller.close();
|
|
} catch (err) {
|
|
logger.warn("Failed to close audit SSE stream", { err });
|
|
}
|
|
},
|
|
});
|
|
|
|
return new Response(stream, {
|
|
headers: {
|
|
"Content-Type": "text/event-stream",
|
|
"Cache-Control": "no-cache",
|
|
Connection: "keep-alive",
|
|
},
|
|
});
|
|
},
|
|
);
|