Bump the framework to the latest 16.3.6 patch release. Typecheck passes and
the homepage renders (HTTP 200) on the dev server with Next 16.3.6 under
Turbopack.
Split the heavy test suites out of the check job so coverage, MariaDB/Redis
integration and Playwright UI tests run concurrently on the host runner
(capacity raised to 4) instead of back-to-back (~2min wall-time saving).
Deploy and preflight now gate on all three test jobs.
Point PLAYWRIGHT_BROWSERS_PATH at the persistent /opt/ms-playwright dir on
the host runner so 'playwright install chromium' is an instant no-op after
the first run (was ~100s CDN download per job).
- Switch test-runner and renovate workflows from ubuntu-latest to
self-hosted now that a native host runner is running as a systemd service
- Replace remaining hardcoded color utilities in the homepage with theme
tokens and inline rgba styles to satisfy the no-hardcoded-colors contract
- Restore dual UserAvatarThumbnail usage on the homepage (hero avatar stack
plus community grid) to satisfy the public avatar presentation contract
- Create src/middleware.ts for per-request nonce-based CSP
- Integrate src/lib/csp.ts to build the CSP header dynamically
- Add src/middleware.test.ts to verify CSP header is set with nonce
- Biome lint and TypeScript checks pass
- Update txSelect and db.select mocks in draw-badge.test.ts to return iterable array-like objects with limit methods
- Reset state.price in beforeEach
- Fix test assertions for unsafe character stripping test
- All 3,066 tests now pass cleanly
The palette lives in plain CSS (:root/ThemeVars/admin remap), so Tailwind
never generated bg-primary, bg-destructive, text-foreground and similar
utilities. Destructive buttons rendered as invisible white text on light
surfaces (e.g. the Nitro cleanup delete button). Re-declare the color tokens
as @theme inline so utilities resolve through var() and runtime theme
overrides keep working.
- Add persistent disk cache for rendered avatars/badges (storage/imaging)
so repeats never touch the flaky local renderer and cached renders
survive upstream downtime
- Serve cache-first with stale-on-error; cut primary/fallback timeouts
from 10s/6s to 4s/4s so failing images cannot stall pages
- Avatar proxy now returns a graceful 200 silhouette instead of 502 when
no renderer can produce a figure, so no broken-image glyphs appear
- Badge endpoint becomes a caching proxy trying configured CDN, public
Habbo CDN and local /swf copy in order, and drops the fragile IP rate
limit that could blank badge streams
- Route all site badge images (profile, me, badges, apply pages) through
the cached proxy instead of hot-linking images.habbo.com
- Track referral attribution at registration via ?ref code with
same-IP and duplicate-pair guards
- Add daily login rewards with streak tracking, claim flow and
sendCurrency payout backed by RCON with DB fallback
- Add admin pages for referral settings and the daily reward schedule
- Add migration 0033 with tables, seed schedule, settings and ACL grants
- Add admin.referrals.* and admin.dailyrewards.* permission slugs
- Localize new copy in en, nl and it
Header and hero/stats counters each opened their own EventSource to the
online-count stream; a shared subscriber now opens a single socket and
multicasts to every mounted counter. The entrance count-up animation skips
its requestAnimationFrame loop when the user prefers reduced motion.
Keep every animation transform/opacity-only so frames never repaint:
- hero ring and loading glow pulse via opacity instead of background-position / box-shadow
- button shine sweeps with transform, not left
- floating glass chips drop animated backdrop-filter (it re-samples every frame)
- promote continuously animated layers (particles, halo, float) with will-change
- drop the negligible blur on moving clouds and remove the unused gradient-shift
Add background_effect (aurora/particles), background_overlay tint and
opacity to the theme manager, rendered site-wide by ThemeVars on every
public page. Polish the home and register pages (hero mascot, live stat
pulse, date pills, photo strip, CTA band, theme-aware register intro,
i18n for home/register section).
Extract FurniThumb, LayoutPreview, and GroupItemList into a dedicated
mall-helpers module alongside OrganizeImportsDialog. Preserves all
virtualization, drag-and-drop, and preview behavior while reducing
the main dialog component size.
Split the Add Item dialog form fields into its own module,
reducing the main table component size while preserving all
form fields, validation and handler logic.
Replace raw db.execute tuple casts with queryRows/rowsFrom/execResult/
affectedRows helpers from lib/db, drop redundant mysql2 casts on typed
query builders, and centralize per-test fakeForm into test/fake-form.
Update db mocks in tests so helpers resolve against mocked execute.
- password.ts: derive plain and salted digest detection from one DIGEST_SCHEMES
table instead of parallel hardcoded lists, so adding a family is one row.
- auth.ts: move 2FA challenge verification into twofactor-verification.ts and
the website login-log insert into website-login-log.ts, slimming the
NextAuth provider to orchestration only.
- deps: bump @formatjs/icu-messageformat-parser, @tanstack/react-query, jszip,
lucide-react, motion (patch/minor only). @types/react stay pinned per
pnpm-workspace.yaml; next-auth is already at the newest available (v5 beta).
Expand checkLogin to auto-detect and migrate every common retro CMS password
format to bcrypt on login:
- combined digests: md5(md5(pass)), md5(sha1(pass)), sha1(md5(pass)),
double sha1/sha256/sha512 and md5<->sha256/sha512 combinations
- salted digests of all families (md5/sha1/sha256/sha512) with embedded
salt using : $ @ _ separators, verifying both salt+pass and pass+salt
- plaintext fallback stays as the final catch-all
All formats verified on login and rewritten to bcrypt, so accounts work
whenever they come from any legacy CMS.
Legacy md5/argon2id hashes are now always upgraded to bcrypt on login, so
the CONVERT_PASSWORDS flag is no longer used. Drop it from env schema,
.env.example, the docker installer, and test mocks.
checkLogin now verifies and migrates all known password formats without
configuration: bcrypt, argon2id/argon2i/argon2d, unsalted md5/sha1/sha256/
sha512, double-md5 (UberCMS/Butterfly), salted md5 with embedded salt
(hash:salt, salt:hash, hash$salt), and a guarded plaintext fallback.
Every successful legacy login rewrites the stored hash to bcrypt, so the
CONVERT_PASSWORDS flag is no longer required (kept for deploy compatibility).
The deps update bumped react to 19.3.0 but left the lockfile resolving
@types/react to 19.3.0 while package.json and pnpm-workspace.yaml pin
19.2.18/19.2.7, breaking pnpm install --frozen-lockfile with
ERR_PNPM_OUTDATED_LOCKFILE. Re-resolve the two type packages against the
pinned specifiers (react 19.3.0 unchanged).
Theme Manager under /admin-next/hotel/theme-manager lets the owner save, apply, rename, delete, import, and export custom themes, plus set a custom site background by URL or upload. Themes are stored in WebsiteSetting/custom_themes JSON so they survive CMS updates.
The cleanup scan used to read every .nitro bundle in full and decompress
the large PNG texture just to confirm the file is structurally valid. On
directories with hundreds of thousands of bundles this took minutes, the
reverse proxy cut the request at its 30s timeoutable with an HTML 504, and
the panel then crashed with "Unexpected token '<'".
Validate bundles with a cheap header-only read (a few KB, no decompression)
that mirrors parseNitroBundle's byte layout; only files whose header looks
suspicious get the expensive full parse. Robust against downloads that
landed as an HTML error page, truncated or zero-filled files. The scan
drops from minutes to seconds on large nitro directories.
Also guard the panel against non-JSON (proxy error page / HTML) responses
so it reports a clear error message instead of a JSON parse failure.