Remove import/repair feature and related API routes.
Local Build and Deploy / deploy (push) Successful in 1m41s

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
SimoandCursor committed 2026-07-17 18:52:38 +02:00
1 parent bb7d581084
commit 49d204e85c
9 files changed
+2 -1468

No files matched your search

@@ -1,11 +0,0 @@
import { withAdmin } from "@/lib/api-handler";
import { apiOk } from "@/lib/api-response";
import { PERMS } from "@/lib/permissions";
import { auditImportedAssets } from "@/lib/services/furni-repair";
// Audit is expensive (scans every imported item's files on disk).
// Using POST keeps it out of any cache layer that might front GET.
export const POST = withAdmin({ permission: PERMS.ASSETS_IMPORT }, async () => {
const summary = await auditImportedAssets();
return apiOk(summary as unknown as Record<string, unknown>);
});
-135
View File
@@ -1,135 +0,0 @@
import { withAdmin } from "@/lib/api-handler";
import { apiError } from "@/lib/api-response";
import { PERMS } from "@/lib/permissions";
import { repairItem } from "@/lib/services/furni-repair";
import { rcon } from "@/lib/services/rcon";
/**
* SSE batch repair route.
* Body: { classnames: string[], concurrency?: number }
* Streams one `data: {...}` event per item.
*/
export const POST = withAdmin(
{ permission: PERMS.ASSETS_IMPORT },
async (request) => {
const body = await request.json();
const classnames: string[] = Array.isArray(body.classnames)
? body.classnames
: [];
// Bumped default to 6 (cap 8). Since downloadFile no longer retries on
// deterministic 404s, misses complete in ~1 request instead of ~4 × 15s.
const concurrency = Math.min(Math.max(body.concurrency || 6, 1), 8);
if (classnames.length === 0) return apiError("No classnames provided", 400);
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
const send = (data: unknown) => {
try {
controller.enqueue(
encoder.encode(`data: ${JSON.stringify(data)}\n\n`),
);
} catch {
/* stream closed */
}
};
const startTime = Date.now();
send({ type: "repair_start", total: classnames.length });
let succeeded = 0;
let failed = 0;
let partial = 0;
let unrepairable = 0;
for (let i = 0; i < classnames.length; i += concurrency) {
const chunk = classnames.slice(i, i + concurrency);
const promises = chunk.map(async (classname) => {
send({ type: "repair_progress", classname, status: "working" });
try {
const result = await repairItem(classname);
if (result.unrepairable) unrepairable++;
if (result.ok) {
succeeded++;
send({
type: "repair_progress",
classname,
status: "done",
nitroRepaired: result.nitroRepaired,
iconRepaired: result.iconRepaired,
warnings: result.warnings,
});
} else {
// Counts as partial if at least one asset was fixed
if (result.iconRepaired || result.nitroRepaired) {
partial++;
send({
type: "repair_progress",
classname,
status: "partial",
nitroRepaired: result.nitroRepaired,
iconRepaired: result.iconRepaired,
warnings: result.warnings,
error: result.error,
unrepairable: result.unrepairable,
});
} else {
failed++;
send({
type: "repair_progress",
classname,
status: "failed",
warnings: result.warnings,
error:
result.error || result.warnings[0] || "Unknown error",
unrepairable: result.unrepairable,
});
}
}
} catch (err) {
failed++;
send({
type: "repair_progress",
classname,
status: "failed",
error: (err as Error).message,
});
}
});
await Promise.allSettled(promises);
}
// RCON refresh so the emulator picks up any items_base changes
try {
await rcon.updateItems();
await rcon.updateCatalog();
} catch {
/* non-fatal */
}
send({
type: "repair_complete",
succeeded,
partial,
failed,
unrepairable,
duration: Date.now() - startTime,
});
controller.close();
},
});
return new Response(stream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive",
},
});
},
);