fix(catalog): check source assets and offer reachable import alternatives
CI / check (push) Failing after 19s
CI / deploy (push) Skipped
CI / e2e (push) Skipped

This commit is contained in:
Simo committed 2026-09-05 14:56:04 +02:00
1 parent 8c1efae296
commit 159b1f7d1b
10 files changed
+646 -56

No files matched your search

+42 -49
View File
@@ -619,45 +619,6 @@ export async function importSingleFurni(params: {
const bestRevision = revision || officialHabbo?.revision || 0;
const bestCategory = category || officialHabbo?.category || "unknown";
// ── Insert into DB with enriched data ──────────────────────────────
onProgress?.("writing_db");
try {
if (preservingExisting) {
warnings.push(
`Existing furniture #${itemId}: SQL settings and catalog offers preserved`,
);
} else if (isUpdate) {
// NOTE: live Arcturus `items_base` has no description/revision/rare columns —
// those metadata fields are persisted in FurnitureData.json (see entry below),
// not in the DB. Only refresh the columns this import manages.
await db.execute(sql`
UPDATE items_base SET sprite_id = ${spriteId}, public_name = ${bestName}, item_name = ${classname}, type = ${itemType}
WHERE id = ${spriteId}
`);
} else {
itemId = await reserveFurnitureId(
originalId,
classname,
async (allocatedId) => {
await db.execute(
sql`INSERT INTO items_base (id, sprite_id, public_name, item_name, type) VALUES (${allocatedId}, ${allocatedId}, ${bestName}, ${classname}, ${itemType})`,
);
},
);
spriteId = itemId;
if (spriteId !== originalId)
warnings.push(
`Source ID ${originalId} is occupied; imported with local ID ${spriteId}`,
);
}
} catch (err) {
return {
ok: false,
warnings,
error: `DB ${isUpdate ? "update" : "insert"} failed: ${(err as Error).message}`,
};
}
// ── Derive file-safe names ────────────────────────────────────────
const rev = bestRevision;
const assetTargets = await getFurniAssetWriteTargets();
@@ -828,7 +789,7 @@ export async function importSingleFurni(params: {
.catch(() => null);
const nitroValid = nitroStat && nitroStat.size >= 128;
if (!nitroValid && !conversionResult) {
if (!nitroValid) {
if (nitroStat) {
warnings.push(
`Nitro file too small/corrupt (${nitroStat.size} bytes) — removing`,
@@ -839,24 +800,56 @@ export async function importSingleFurni(params: {
/* ignore */
}
}
try {
if (!isUpdate)
await db.execute(
sql`DELETE FROM items_base WHERE id = ${itemId} AND item_name = ${classname}`,
);
} catch {
/* best effort cleanup */
}
return {
ok: false,
warnings,
error: `${isUpdate ? "No .nitro file could be created; existing furniture was preserved" : "Import rolled back: no .nitro file could be created"} (${classname}, revision ${rev}). ${warnings
error: `${isUpdate ? "No .nitro file could be created; existing furniture was preserved" : "Import not started: no .nitro file could be created"} (${classname}, revision ${rev}). ${warnings
.filter((warning) => /conversion|download|SWF/.test(warning))
.slice(-3)
.join(". ")}`,
};
}
// ── Insert into DB with enriched data ──────────────────────────────
onProgress?.("writing_db");
try {
if (preservingExisting) {
warnings.push(
`Existing furniture #${itemId}: SQL settings and catalog offers preserved`,
);
} else if (isUpdate) {
// NOTE: live Arcturus `items_base` has no description/revision/rare columns —
// those metadata fields are persisted in FurnitureData.json (see entry below),
// not in the DB. Only refresh the columns this import manages.
await db.execute(sql`
UPDATE items_base SET sprite_id = ${spriteId}, public_name = ${bestName}, item_name = ${classname}, type = ${itemType}
WHERE id = ${spriteId}
`);
} else {
itemId = await reserveFurnitureId(
originalId,
classname,
async (allocatedId) => {
await db.execute(
sql`INSERT INTO items_base (id, sprite_id, public_name, item_name, type) VALUES (${allocatedId}, ${allocatedId}, ${bestName}, ${classname}, ${itemType})`,
);
},
);
spriteId = itemId;
if (spriteId !== originalId)
warnings.push(
`Source ID ${originalId} is occupied; imported with local ID ${spriteId}`,
);
}
} catch (err) {
return {
ok: false,
warnings,
error: `DB ${isUpdate ? "update" : "insert"} failed: ${(err as Error).message}`,
};
}
await Promise.all([
mirrorFileToDirs(swfPath, `${safeSwfName}.swf`, mirrorSwfDirs, warnings),
mirrorFileToDirs(