- Integrate DownloadRegistry into concurrent download limit
and clean up timers on removal/clear
- Wrap MetadataSyncService batch deletes in single transaction
- Always re-throw checksum errors in RuffleService to prevent
verification bypass
- Fix system-settings early return skipping second job update
when first cron expression is invalid
- Increase DatabaseService hot-reload grace period to 30s
- Add permission guard to metadata sync status endpoint
- Use encodeURIComponent for game launch content URLs
- Clamp limit params to minimum of 1 in jobs routes
- Use non-null assertion for authenticated user permissions
- Fix ConfirmDialog not calling onCancel on overlay dismiss
- Guard FormattedDate against invalid date strings
- Add breadcrumbContext to GameListItem memo comparison
- Fix MetadataUpdateCard stale closure in interval callback
- Move Dockerfile healthcheck to docker-compose for flexibility
- Fix build:analyze script to set VITE_ANALYZE env var
- Move health check from Dockerfile to docker-compose
for easier override
- Remove unused VITE_API_URL build arg from frontend
Dockerfile
- Simplify build:analyze and check-bundle scripts
- Document PUID/PGID container permissions in
.env.example
- Pin DNS resolution to prevent SSRF rebinding between
check and connect (GameDataDownloader)
- Fail-closed on realpath failure in GameZipServer
- Zip Slip validation before extraction (RuffleService)
- Escape LIKE wildcards in ActivityService queries
- Sanitize sort order to prevent SQL injection
- Whitelist sort order instead of passing raw user input
- Add headersSent guard to global error handler
- Remove cookie from CGI allowed headers, sanitize
content-type against null/CR/LF injection
- Revoke refresh tokens on password change and user
deactivation
- Wrap role/user uniqueness checks in transactions
(TOCTOU fix)
- Fix concurrent ZIP mount race with deferred promise
and double-close prevention via _manuallyClosed flag
- Handle client disconnect in collectRequestBody
- Tighten nginx CSP, repeat headers in location blocks,
hide server version, pin nginx:1.27-alpine
- Fix health check endpoint path in backend Dockerfile
- Use wget instead of curl for frontend health checks
- Replace any types with proper types across backend
and frontend
- Replace || with ?? for config/form defaults
- Replace hardcoded Tailwind colors with theme tokens
- Replace console.log/error with logger in ErrorReporter
and ChartErrorBoundary
- Conditionally render AddToPlaylistModal to avoid
hidden instances
- Add NaN guards for parseInt in GameBrowseLayout
- Standardize query key for publicSettings
- Simplify README to Docker-first quickstart with wiki
link
- Fix license to GPL-3.0 in backend package.json
- Slow down particle animation speed
- Add Zod max-length limits on playlist/error schemas
- Ensure positive limit in parsePaginationQuery
- Validate settings category param against allowlist
- Fix static/parameterized route ordering in favorites
- Add asyncHandler to game-zip wildcard route
- Close readline/stream on error in getRecentErrors
- Add .catch() on fire-and-forget syncAndReload
- Fix LazyBackgroundImage cleanup on unmount
- Store NetworkStatusIndicator timeout in ref
- Add Flash/SWF condition to random game query
Routes game content through nginx instead of requiring direct
localhost:22500 access from browser. This enables proper Docker
networking where containers communicate internally.
Changes:
- Add /game-proxy and /gamezip-proxy locations to nginx config
- Add GAME_SERVICE_EXTERNAL_URL config for browser-facing URLs
- Update games route to use external URL config
- Add GAME_SERVICE_HOST env var to frontend container
- Add game-service dependency to frontend in docker-compose