feat(import): run catalog synchronizations as durable jobs
CI / check (push) Successful in 57s
CI / deploy (push) Successful in 18s
CI / publish-container (push) Successful in 1m18s

This commit is contained in:
Simo committed 2026-09-11 00:36:22 +02:00
1 parent a2954e4408
commit 76f0420d64
14 files changed
+559 -801

No files matched your search

@@ -1,97 +1,8 @@
import { withAdmin } from "@/lib/api-handler";
import { db, ItemsBase } from "@/lib/db";
import { PERMS } from "@/lib/permissions";
import { importSingleFurni } from "@/lib/services/furni-import";
import { getOfficialHabboFurnidata } from "@/lib/services/habbo-furnidata-cache";
import { runSseBatch } from "@/lib/services/import/core/sse-batch";
import { enqueueFurnitureSync } from "@/lib/services/furni-sync-queue";
export const POST = withAdmin(
{ permission: PERMS.ASSETS_IMPORT },
async (request) => {
// Haal alle officiële furnidata
const furnidata = await getOfficialHabboFurnidata();
// Haal alle bestaande classnames uit de database
const existingClassnames = new Set(
await db
.select({ itemName: ItemsBase.itemName })
.from(ItemsBase)
.then((rows) => rows.map((r) => r.itemName)),
);
// Filter naar alleen items die niet in de database staan
const missingItems = Array.from(furnidata.entries())
.filter(([, entry]) => !existingClassnames.has(entry.classname))
.map(([, entry]) => ({
classname: entry.classname,
name: entry.name,
description: entry.description ?? "",
type: entry.category === "wallitem" ? "wallitem" : "flooritem",
revision: entry.revision ?? 0,
category: entry.category ?? "unknown",
}));
if (missingItems.length === 0) {
return new Response(
JSON.stringify({
success: true,
message: "All items are already in the database",
imported: 0,
}),
{
headers: { "Content-Type": "application/json" },
},
);
}
if (missingItems.length > 500) {
return new Response(
JSON.stringify({
success: false,
message: `Too many missing items (${missingItems.length}). Consider importing in smaller batches.`,
}),
{
headers: { "Content-Type": "application/json" },
status: 400,
},
);
}
// Importeren via SSE batch
return runSseBatch({
items: missingItems,
concurrency: 3,
signal: request.signal,
labelOf: (it) => it.classname,
worker: async (it, _index, report) => {
const result = await importSingleFurni({
id: 0,
classname: it.classname,
name: it.name,
description: it.description,
type: it.type,
revision: it.revision,
category: it.category,
onProgress: report,
});
if (result.ok) {
return {
ok: true,
warnings: result.warnings,
error: result.error,
};
}
return {
ok: false,
warnings: result.warnings,
error: result.error,
};
},
flush: async () => {
// FurnitureData.json wordt automatisch geschreven door importSingleFurni
},
});
},
(request, ctx) =>
enqueueFurnitureSync(request, ctx.session.user.id, "official"),
);