feat: add manual 'verify & fix all interactions' admin tool
CI / check (push) Successful in 26s
CI / release (push) Skipped
CI / deploy (push) Successful in 54s

New POST /api/admin/import/furni/verify re-runs the full interaction
verification over items_base at any time, plus a Tools dropdown entry
in the furni import admin. It corrects interaction_type,
interaction_modes_count and allow_sit/lay/walk against real furniture
data (furnidata flags + .nitro animation states); items without real
data are skipped and existing emulator handler types are preserved.
This commit is contained in:
openhands committed 2026-08-19 21:11:38 +02:00
1 parent 0b1d3b24c2
commit 2b9a015afb
3 files changed
+151

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -0,0 +1,18 @@
import { withAdmin } from "@/lib/api-handler";
import { apiOk } from "@/lib/api-response";
import { PERMS } from "@/lib/permissions";
import { verifyAndFixInteractionModesCount } from "@/lib/services/furni-import";
/**
* POST /api/admin/import/furni/verify
*
* Re-runs the interaction verification over the ENTIRE items_base table,
* correcting interaction_type, interaction_modes_count and allow_sit/
* allow_lay/allow_walk against the real furniture data (furnidata flags +
* .nitro animation states). Only items with authoritative data are touched —
* no keyword guesses, so no false positives.
*/
export const POST = withAdmin({ permission: PERMS.ASSETS_IMPORT }, async () => {
const result = await verifyAndFixInteractionModesCount();
return apiOk(result);
});
+40
View File
@@ -0,0 +1,40 @@
export const VERIFY_INTERACTIONS_URL = "/api/admin/import/furni/verify";
export interface VerifyInteractionsResult {
fixed: number;
checked: number;
skipped: number;
errors: string[];
}
type AdminFetcher = (
input: RequestInfo | URL,
init?: RequestInit,
) => Promise<Response>;
export async function requestVerifyInteractions(
fetcher: AdminFetcher,
): Promise<VerifyInteractionsResult> {
const response = await fetcher(VERIFY_INTERACTIONS_URL, { method: "POST" });
const payload = (await response.json()) as Record<string, unknown>;
if (!response.ok) {
throw new Error(
typeof payload.error === "string"
? payload.error
: "Interaction verification failed",
);
}
const errors = Array.isArray(payload.errors)
? payload.errors.filter(
(value): value is string => typeof value === "string",
)
: [];
return {
fixed: Number(payload.fixed) || 0,
checked: Number(payload.checked) || 0,
skipped: Number(payload.skipped) || 0,
errors,
};
}