- Fix proxy routes to use resolveImagerBase instead of removed resolveUpstreamBase
- Fix avatarImageUrl type signature to use AvatarOptions
- Run biome formatter
- Update imager to use epicnabbo.nl by default with effect=14 and img_format=apng
- Add figure string converter (old Habbo format -> epicnabbo.nl short format)
- Update avatarImageUrl to auto-convert figure strings
- Update online-users-widget to use new avatarImageUrl
- Add tests for imager and figure conversion
- Self-host Nunito and Pixelify Sans via next/font instead of Google Fonts CDN
(removes render-blocking external stylesheets and preconnects)
- Remove stale mariadb entry from serverExternalPackages (app uses mysql2)
- Exclude unused src/generated Prisma client from typecheck and remove it
- Add unit tests for swf-parser, effectmap and figuremap (0% coverage -> 90%+)
- Merge type and value imports from the same module into single imports
- Remove dead import-badges action (flow uses /api/admin/import/badges)
- Remove unused babel-plugin-react-compiler devDependency
- Remove stray test.txt file
- Update knip config: track css imports, drop redundant ignore entries
- Update contract test to drop obsolete dead-action assertion
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).