Skip to content

v0.4.2

Choose a tag to compare

@github-actions github-actions released this 03 Sep 03:00
· 10 commits to main since this release

Patch release: un-bricks plain-http self-hosts.

Fixed

  • Plain-http self-hosts were stuck on "Loading…". v0.4.1 added upgrade-insecure-requests + HSTS to the production CSP unconditionally. Browsers honour the upgrade directive even on http:// origins, so a LAN install at http://192.168.x.x:3000 had every /_next/static chunk rewritten to https:// and failing with ERR_SSL_PROTOCOL_ERROR — no JS ran, so the page never hydrated past the SSR "Loading…" fallback. Both directives are now opt-in via STAYBATTLE_HTTPS=true (a build-time flag / Docker build arg) for TLS-terminated deployments. Header logic moved to src/lib/security-headers.ts with vitest coverage.
  • Plain-http self-hosts answered "Sign in first" to every action. The voter cookie was secure: NODE_ENV === "production"; browsers drop Secure cookies on any non-localhost http origin, so at http://192.168.x.x:3000 sign-in stuck client-side but the server never saw a session — "Start the battle", voting, everything refused. Secure is now gated on the same STAYBATTLE_HTTPS=true flag (read at run time; the Dockerfile carries it into the runtime stage). Cookie attributes moved to a tested voterCookieOptions() helper.
  • Public demo showed "checking…" on every listing forever. scripts/admin/reset-demo.mjs wiped the whole settings table, which dropped the availability_reset_v1 flag that db.ts checks at boot — so the next container restart re-ran the one-shot availability wipe and nulled every status the reset had just baked. The reset now re-arms the flag inside its own transaction. Integration test runs the real script against a temp DB.
  • Demo mode no longer scrapes Airbnb. addListing was not demo-gated, so any visitor could make the public demo fetch airbnb.com (README had claimed the scrape was skipped). addListing and refreshAvailability now refuse up front in STAYBATTLE_DEMO_MODE with a message saying why.
  • Re-check buttons surface refusals. Both AvailabilityPanel and the BattleHeader "recheck all dates" button ignored the action result, so a refused recheck (demo mode, missing trip dates) either showed "checking 0 of N…" until a timeout or silently did nothing. Both now show the error inline.
  • "New code" / "Kick" silently did nothing on refusal. InviteCodePanel ignored the action result, so an expired session or a non-organizer cookie made the confirm dialog close with no visible effect. Refusals now render inline.
  • Demo modal header was a black smear in light mode. Its bg-gradient-to-br … via-zinc-950 gradient wasn't covered by the light-theme surface remap (which can't reach gradient stops). Tagged with the existing .sb-deep-surface helper so it swaps like the other dark gradient surfaces.

Added

  • Stale battles archive themselves. A battle whose check-out day ended more than 7 days ago is moved to the trophy case on the next page load, exactly as the organizer's "close battle" does (listings, pins, participants, and trip dates cleared). Before, a trip that ended months ago blocked the whole one-battle-per-server instance until its organizer signed in with their PIN. Battles with no dates never go stale. isStale() in src/lib/battle.ts (unit-tested) + a shared closeCurrentBattle() in battle-server.ts used by both paths (DB-level test).

Changed

  • Demo discloses what is simulated. Sign-in screen gets a "Public demo" hint (anonymous visitors never saw the demo modal), the demo modal explains that badges / votes / comments are seed data, and the footer disclaimer has a demo-mode variant instead of claiming badges were "scraped from Airbnb's public page".
  • vitest.config.ts aliases the server-only marker package so server-action modules can be imported in tests.