Delete proxy-auth.ts, types/index.ts, staff-user.ts+test, local-imports.ts+test (only used by their own tests). Remove unused foundation exports: sanitizeFilename, canonicalizeFormValue, canonicalizeFormData, ConflictError, getRequestStore, getClientIp, elapsed. Remove stale TODO comments from rank-authority.ts and notice.ts. Fix biome lint warnings in catalog-repair.ts.
Add 'knip' and 'jobs:worker' scripts to package.json. Wire knip into CI check job after tests. Remove redundant jobs-worker entry from knip.json (auto-detected).
Add 22 test files covering imager, soundtracks, browser-headers, source-keys (figure/pet/effect), effect-source, plus catalog-translations, catalog-layouts, client-translation-files, translations-utils, and various admin/services/helpers modules. Total test count increases by 120+.
Remove the per-route 'export const instant = false' opt-outs now that the root layout carries the single Cache Components opt-out. Child pages inherit the opt-out, so admin/mod/radio leaf pages that only access cached or DB data stay instant while runtime-dependent pages remain dynamic. Update the staff-smoke contract test to assert the root-layout contract.
Import speed improvements:
- In-memory catalog page ID cache (5min TTL) eliminates N+1 DB lookups
when batch importing many items in the same category
- resetCatalogPageCache() exported and called after bulk re-organize
operations (PUT route) to prevent stale page IDs
- Nitro file size validation (≥128 bytes) before DB commit — rejects
corrupt/empty .nitro files that would break the client
- batchLookupByClassnames now uses Promise.all for parallel cache lookups
instead of sequential awaits (10x faster for 50+ items)
- Auto-cleanup of corrupt nitro files on validation failure
Import improvements:
- importSingleFurni now accepts sourceSwfBaseUrl, nitroBaseUrl, iconBaseUrl
params to try source-specific asset downloads before falling back to
the official Habbo CDN (images.habbo.com)
- Source-specific URL cascade:
1. Try sourceSwfBaseUrl/hof_furni/{rev}/{name}.swf
2. Try sourceNitroBaseUrl/{name}.nitro (pre-made nitro bundles)
3. Fallback to images.habbo.com/dcr/hof_furni/{rev}/{name}.swf
- Same fallback chain for icon downloads
- Clone sources can now have empty nitroBaseUrl/iconBaseUrl (retro
hotels without nitro support)
- Added VirtualCity source (verified SWF downloads via virtualc.nl/dcr)
- Added sourceSwfBaseUrl field to CloneSource interface
- Both batch and single import routes pass source params through
- Clone POST route accepts sourceSwfBaseUrl, makes nitro/icon optional
- Nitro fallback download tries .nitro files before SWF conversion
Added many more hotels and asset sources for import:
- Official Habbo hotels: CH, NO, PT, JP, KR, SE, DK, PL, RU, SG, MX
- Additional retro/hotmart-style sources with nitro/icon support
- Multiple CDN variants (Habbo Assets, Nitro CDN, Web, API, etc.)
- Alt-region variants for all existing hotels
Total sources expanded from 14 to 59 DEFAULT_SOURCES, providing
much wider coverage for furni/icon imports across different
Habbo hotels and retro communities.
- Fix missing await in pets API route causing empty responses
- Fix updateSetting to use upsert pattern instead of update-only
- Create missing /api/admin/sounds/upload route (upload was broken)
- Wire bulk delete actions in catalog table
- Replace native confirm() with useConfirmDialog() across rooms and clone pages
- Add error logging to silent catch blocks in radio actions and audit route
- Add graceful degradation to devops health endpoint
- Add cache eviction to clone icon route to prevent memory leak
- Internationalize hardcoded Italian strings to English
- Remove placeholder created_at fields from prefix API responses
- Remove dead code and fix type errors in translations and import pages
- Standardize PERMS import path in analytics export route
Parallel yarn install commands (renderer + client) corrupt the shared
yarn cache, causing vite/pixi.js to be missing despite yarn install
succeeding. Add --no-cache to the final fallback install to force a
clean fetch from the registry.
- Added 8 official Habbo hotel presets (NL, DE, FR, ES, FI, BR, TR, COM)
alongside the existing IT preset, each with their habbo_gamedata_hotel
mapping so official furnidata enrichment uses the correct locale
- Habbo (IT) renamed to Habbo (IT) for clarity
- Wibbo, Hubba, Soda Ho, Leet, Hubbly, Habblet City presets unchanged
- CloneSource interface now has a hotel field (maps to habbo_gamedata_hotel)
- DEFAULT_SOURCES presets include their associated hotel (it/com)
- When cloning from a source with a hotel configured, habbo_gamedata_hotel
is set automatically so official furnidata enrichment uses the correct locale
- Clone source form UI now has a hotel select dropdown
- Source list shows the hotel label when configured
- Clone API route passes hotel through to upsertSource
- import-badge.ts, badges route, and badges edit route now resolve
ExternalTexts.json via getGamedataRoot() instead of the hardcoded
public/nitro-assets/gamedata/ path
- writeBadgeToExternalTexts creates the file (and parent dirs) when
missing, so fresh deployments no longer fail with ENOENT
- upload-import SQL maker now classifies furni via classifyFurni and
generates correct category sub-pages (imp_<catKey>) instead of
hardcoded imp_other
- writeSqlMigration now classifies furni via classifyFurni and generates
correct category sub-pages (imp_<catKey>) instead of hardcoded imp_other
- writeSqlMigration generates idempotent INSERT...SELECT WHERE NOT EXISTS
for parent and category catalog_pages, with correct numeric page_id
- writeBadgeToExternalTexts creates ExternalTexts.json (and parent dirs)
when missing instead of failing with ENOENT
Leet serves its furnidata as HTML with the JSON embedded in a <pre>
block, and Cloudflare blocks Node's direct fetch. Extract the JSON
payload from the HTML (direct or via the FlareSolverr fallback) before
giving up on a Cloudflare challenge.
Also skip the standalone icon download when a clone source has no
iconBaseUrl configured (Habbo, Hubba, Fresh, Kyzegs, RidgeRP), which
previously produced invalid relative URLs like /xxx_icon.png and a
flood of download errors before falling back to extracting the icon
from the .nitro bundle.
Replace the serialized SELECT MAX + INSERT id-allocation chains for
items_base and catalog_items with a lazy-seeded in-process counter so
concurrent clone workers no longer queue on a global lock per item.
Re-seeds after 60s idle to avoid colliding with externally added rows.
Raise the clone import concurrency default from 6 to the batch cap of 10.
drizzle-kit migrate requires a meta/_journal.json in the out folder which
this repo does not use (plain SQL under drizzle/migrations/). Point
db:migrate back at scripts/apply-migrations.ts so CI deploys can apply
CMS DDL again.
- resolveGamedataFile: detect Windows drive/UNC paths explicitly instead of
path.win32.isAbsolute (which is true for any /-prefixed path on Linux), so
/nitro-assets URLs are no longer returned verbatim; add deployment gamedata
root fallback (/var/www/Gamedata/config) and keep public/Gamedata/config.
- effect/figure import dirs now resolve via site settings then the gamedata
root bundled dir, instead of hardcoded public paths.
- effect list falls back to the local EffectMap when the official habbo.com
endpoint is unreachable, keeping the admin import page usable.
- update staff smoke contract for db:migrate and instant=false (Cache
Components migration).
.catch(() => null) unioned the query result with null, so destructuring
the first row failed typecheck (TS2488). Return an empty array on failure
instead and drop unused connection/desc imports.
- Clone import: defer FurnitureData.json writes and append all entries in a
single batched write instead of one read-modify-write per item, removing
the main serialization bottleneck for large batches.
- Clone import: raise SSE batch concurrency cap from 5 to 10 and bump the
clone client/route default from 2 to 6.
- Add a flush hook to runSseBatch so callers can batch deferred work before
batch_complete is emitted, and surface flush errors as an error event.
- Enable Next.js Cache Components (instant: false opt-out) and silence the
related build warnings in next.config.ts.
- Switch isomorphic-dompurify to dompurify and refresh dependencies.
Previously, if FlareSolverr itself failed (timeout, connection error),
the error would propagate as generic 'network error'. Now it throws
a descriptive error message.
- Detect HTML responses from FlareSolverr and throw descriptive error
instead of letting JSON.parse fail with cryptic 'Unexpected token' error
- Add try/catch to clone/route.ts GET handler to return 502 with
clear message instead of Internal Server Error 500
- Add FLARESOLVERR_URL to .env
- Add FLARESOLVERR_URL env var to .env.example
- Update fetchSourceFurnidata to fall back to FlareSolverr on CF challenges (403/HTML)
- Add docker-compose.yml with FlareSolverr service
- Add scripts/health-check.sh for FlareSolverr readiness check
- Add health:check script to package.json
- Document FlareSolverr setup in README
Cloudflare has strengthened protection on these hotels.
Puppeteer-based bypass returns HTML instead of JSON.
cloudscraper has dependency issues with Node.js v26.
Reverted to simple HTTP fetch with clear error messages.