feat(catalog): repair missing furniture components with verified status
CI / check (push) Successful in 1m33s
CI / deploy (push) Successful in 1m22s
CI / e2e (push) Successful in 24s

This commit is contained in:
Simo committed 2026-09-05 18:12:34 +02:00
1 parent 3c24df9b1d
commit 570f3dde44
13 files changed
+438 -164

No files matched your search

+1
View File
@@ -9,6 +9,7 @@ export interface ImportJobItem {
attachmentId?: string;
}
export interface ImportJob {
mode?: "repair";
id: string;
userId: number;
createdAt: string;
+36
View File
@@ -65,3 +65,39 @@ describe("studio inspection", () => {
).toBe("conflict");
});
});
import { furnitureHealth } from "./studio-inspection";
it("does not call SQL-only furniture complete", () => {
expect(
furnitureHealth({
...empty,
sql: [{ id: 1, spriteId: 2, name: "chair", type: "s" }],
}),
).toMatchObject({
state: "incomplete",
missing: ["Nitro", "Icon", "Furnidata", "Catalog offer"],
});
});
it("keeps inaccessible assets unverified", () => {
expect(
furnitureHealth({ ...empty, nitro: { exists: null, bytes: 0 } }).state,
).toBe("unknown");
});
it("detects mismatched local sprite IDs", () => {
expect(
furnitureHealth({
...empty,
sql: [{ id: 1, spriteId: 2, name: "chair", type: "s" }],
furnidata: [
{
id: 3,
name: "chair",
description: "",
revision: 1,
type: "flooritem",
},
],
}).state,
).toBe("conflict");
});
+34
View File
@@ -68,3 +68,37 @@ export function compareFurniture(
: "present";
return { state, fields } as const;
}
export function furnitureHealth(local: FurnitureInspection) {
const missing: string[] = [];
if (local.nitro.exists === false) missing.push("Nitro");
if (local.icon.exists === false) missing.push("Icon");
if (local.furnidataReadable && !local.furnidata.length)
missing.push("Furnidata");
if (!local.sql.length) missing.push("SQL item");
if (!local.catalog.length) missing.push("Catalog offer");
const sql = local.sql[0],
fd = local.furnidata[0];
const conflict =
local.sql.length > 1 ||
local.furnidata.length > 1 ||
!!(
sql &&
fd &&
(sql.spriteId !== fd.id ||
(sql.type === "i" ? "wallitem" : "flooritem") !== fd.type)
);
const unknown =
!local.furnidataReadable ||
local.nitro.exists === null ||
local.icon.exists === null;
const state = conflict
? "conflict"
: unknown
? "unknown"
: !missing.length
? "complete"
: missing.length === 5
? "new"
: "incomplete";
return { state, missing } as const;
}