feat(studio): expand nitro cleanup with repair, auto-clean, and orphaned assets
CI / check (push) Successful in 4m15s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 1m59s

Scan distinguishes fake, broken, and orphaned SWF/icon assets with age
metadata, deletes per asset kind, re-downloads broken nitro bundles from
configured sources, auto-cleans old fake leftovers, and exports a JSON
manifest. Adds rebuild and auto-clean API endpoints with audit coverage
and a housekeeping preview route under the hotel domain.

Verified: full vitest suite (2213 tests), typecheck, and biome all pass.
This commit is contained in:
openhands committed 2026-09-15 21:59:21 +02:00
1 parent ea4fd375b4
commit 438277a17a
13 files changed
+1118 -155

No files matched your search

@@ -20,7 +20,14 @@ export const hotelManifest = {
PERMS.PAGES_VIEW,
PERMS.CATALOG_EDIT,
),
routes: [],
routes: [
{
id: "nitro-cleanup",
labelKey: "pages.housekeeping.domains.hotel.routes.nitroCleanup",
href: "/admin-next/hotel/nitro-cleanup",
capability: anyCapability(PERMS.ASSETS_IMPORT),
},
],
searchProviders: [],
inboxSources: [],
widgets: [],
@@ -561,7 +561,7 @@ describe("housekeeping foundation completion contracts", () => {
}
});
it("creates the real six-domain registry in locked order without workflows", () => {
it("creates the real six-domain registry in locked order without approved workflows", () => {
const registry = createHousekeepingRegistry(HOUSEKEEPING_MANIFESTS);
expect(registry.domains.map((domain) => domain.id)).toEqual([
@@ -572,9 +572,20 @@ describe("housekeeping foundation completion contracts", () => {
"hotel",
"system",
]);
expect(registry.domains.every((domain) => domain.routes.length === 0)).toBe(
true,
);
expect(
registry.domains
.filter((domain) => domain.id !== "hotel")
.every((domain) => domain.routes.length === 0),
).toBe(true);
expect(
registry.domains.find((domain) => domain.id === "hotel")?.routes,
).toEqual([
expect.objectContaining({
id: "nitro-cleanup",
href: "/admin-next/hotel/nitro-cleanup",
labelKey: "pages.housekeeping.domains.hotel.routes.nitroCleanup",
}),
]);
});
it("keeps production preview disabled even when the flag is true", () => {
@@ -77,6 +77,7 @@ const expectedManifests = [
labelKey: "pages.housekeeping.domains.operations.title",
descriptionKey: "pages.housekeeping.domains.operations.description",
slugs: [PERMS.ADMIN_DASHBOARD, PERMS.ASSETS_IMPORT],
routes: [],
},
{
id: "people",
@@ -108,6 +109,7 @@ const expectedManifests = [
PERMS.MOD_CFH_EDIT,
PERMS.MOD_TICKETS_EDIT,
],
routes: [],
},
{
id: "content",
@@ -131,6 +133,7 @@ const expectedManifests = [
PERMS.SETTINGS_VIEW,
PERMS.SETTINGS_EDIT,
],
routes: [],
},
{
id: "economy",
@@ -144,6 +147,7 @@ const expectedManifests = [
PERMS.CATALOG_EDIT,
PERMS.SHOP_EDIT,
],
routes: [],
},
{
id: "hotel",
@@ -161,6 +165,14 @@ const expectedManifests = [
PERMS.PAGES_VIEW,
PERMS.CATALOG_EDIT,
],
routes: [
{
id: "nitro-cleanup",
labelKey: "pages.housekeeping.domains.hotel.routes.nitroCleanup",
href: "/admin-next/hotel/nitro-cleanup",
capability: { mode: "any", slugs: [PERMS.ASSETS_IMPORT] },
},
],
},
{
id: "system",
@@ -180,6 +192,7 @@ const expectedManifests = [
PERMS.SETTINGS_EDIT,
PERMS.NOTIFICATIONS_EDIT,
],
routes: [],
},
] as const;
describe("housekeeping registry", () => {
@@ -324,7 +337,7 @@ describe("housekeeping registry", () => {
labelKey: expected.labelKey,
descriptionKey: expected.descriptionKey,
});
expect(actual.routes).toEqual([]);
expect(actual.routes).toEqual(expected.routes);
expect(actual.searchProviders).toEqual([]);
expect(actual.inboxSources).toEqual([]);
expect(actual.widgets).toEqual([]);
+7 -1
View File
@@ -586,15 +586,21 @@ export const hotelMigrationEntries: readonly MigrationEntry[] = [
dependencies: {
queries: ["GET /api/admin/studio/nitro-cleanup", "scanFakeBrokenNitros"],
mutations: [
"autoCleanFakeNitros",
"DELETE /api/admin/studio/nitro-cleanup",
"clearFurniImportCache",
"deleteNitroCleanupFiles",
"POST /api/admin/studio/nitro-cleanup/auto-clean",
"POST /api/admin/studio/nitro-cleanup/rebuild",
"repairBrokenNitros",
],
},
auditRequirement: "PRIVILEGED_MUTATION",
localization: "PARTIAL",
accessibility: "PARTIAL",
notes: ["Deletes orphaned or unparseable nitro bundles from asset files"],
notes: [
"Deletes orphaned or unparseable asset files and re-downloads broken nitro bundles from configured sources",
],
}),
plannedHotelEntry({
surface: "admin",