fix(nitro): normalise attached and recovered .nitro bundles too
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 40s
CI / tests-unit (push) Successful in 1m45s
CI / tests-integration (push) Successful in 1m55s
CI / tests-ui (push) Successful in 2m37s
CI / preflight (push) Skipped
CI / deploy (push) Failing after 1m53s

Two more .nitro entry points in the main import path still wrote the
supplied buffer verbatim: an attached `providedNitro` and a bundle pulled
back by `resolveMissingNitro`. Both are real furniture imports, so they
could still land a PNG texture while the SWF, clone and upload paths
produced WebP.

Route both through the same normalisation, falling back to the original
bytes with a warning if the texture cannot be decoded.
This commit is contained in:
openhands committed 2026-09-27 16:00:44 +02:00
1 parent b26e2e0de4
commit 9ee22db8ba
1 file changed
+31 -2
+31 -2
View File
@@ -218,6 +218,26 @@ import { classifyFurni } from "@/lib/furni/auto-catalog";
export { autoPriceFurni } from "@/lib/furni/auto-catalog"; export { autoPriceFurni } from "@/lib/furni/auto-catalog";
import { autoPriceFurni } from "@/lib/furni/auto-catalog"; import { autoPriceFurni } from "@/lib/furni/auto-catalog";
import { toWebpLosslessBundle } from "@/lib/services/swf/nitro-builder";
/**
* Store an incoming .nitro as WebP Lossless, whatever format it arrived in, so
* every import path ends up with the same on-disk format as the SWF importer.
* A texture that cannot be decoded is kept as-is with a warning: the bundle
* itself is valid, and dropping a furniture item over a codec edge case is
* worse than a slightly larger texture.
*/
async function toWebpLosslessOrKeep(
bundle: Buffer,
warnings: string[],
): Promise<Buffer> {
try {
return await toWebpLosslessBundle(bundle);
} catch {
warnings.push("texture kept in its original format");
return bundle;
}
}
/** Get or create a category sub-page under the imported parent page. /** Get or create a category sub-page under the imported parent page.
* Caches category page IDs in-memory for CATEGORY_CACHE_TTL_MS to avoid * Caches category page IDs in-memory for CATEGORY_CACHE_TTL_MS to avoid
@@ -654,7 +674,11 @@ export async function importSingleFurni(params: {
const mirrorNitroDirs = assetTargets.mirrorDirs.map((d) => d.nitroDir); const mirrorNitroDirs = assetTargets.mirrorDirs.map((d) => d.nitroDir);
if (params.providedNitro && !existsSync(nitroPath)) { if (params.providedNitro && !existsSync(nitroPath)) {
await fs.writeFile(nitroPath, params.providedNitro, { flag: "wx" }); await fs.writeFile(
nitroPath,
await toWebpLosslessOrKeep(params.providedNitro, warnings),
{ flag: "wx" },
);
} }
// ── Download assets in parallel (with retry + validation) ──────── // ── Download assets in parallel (with retry + validation) ────────
@@ -816,7 +840,12 @@ export async function importSingleFurni(params: {
if (!existsSync(nitroPath) && params.resolveMissingNitro) { if (!existsSync(nitroPath) && params.resolveMissingNitro) {
await onProgress?.("checking_sources"); await onProgress?.("checking_sources");
const recovered = await params.resolveMissingNitro(rev); const recovered = await params.resolveMissingNitro(rev);
if (recovered) await fs.writeFile(nitroPath, recovered, { flag: "wx" }); if (recovered)
await fs.writeFile(
nitroPath,
await toWebpLosslessOrKeep(recovered, warnings),
{ flag: "wx" },
);
else else
warnings.push( warnings.push(
"No matching bundle was recovered from the checked sources. Review source availability or attach the original .nitro file.", "No matching bundle was recovered from the checked sources. Review source availability or attach the original .nitro file.",