feat: add tournaments and validation and security

This commit is contained in:
2026-03-26 15:36:22 +01:00
parent d76e8922cc
commit 25d2d1af4a
47 changed files with 5175 additions and 58 deletions

View File

@@ -29,6 +29,10 @@ if (!building) {
.then(({ initDMHandler }) => initDMHandler())
.catch((err) => log.dm.warn({ err: err.message }, 'DM handler init skipped'));
import('$lib/server/tournament/scheduler')
.then(({ startTournamentScheduler }) => startTournamentScheduler())
.catch((err) => log.tournament.warn({ err: err.message }, 'Tournament scheduler init skipped'));
process.on('unhandledRejection', (reason) => {
log.http.error({ err: reason }, 'Unhandled rejection');
});
@@ -87,9 +91,22 @@ const handleRequestLogging: Handle = async ({ event, resolve }) => {
// ── Auth + rate limiting ──
const handleBetterAuth: Handle = async ({ event, resolve }) => {
// Rate limiting for API routes: 600 req/min per IP
// Rate limiting for API routes
if (event.url.pathname.startsWith('/api/')) {
const ip = event.getClientAddress();
// Stricter limit for auth endpoints: 10 req/min per IP
if (event.url.pathname.startsWith('/api/auth/')) {
const { ok, retryAfter } = checkRateLimit(`auth:${ip}`, 10, 60_000);
if (!ok) {
return new Response('Too Many Requests', {
status: 429,
headers: { 'Retry-After': String(retryAfter ?? 60), 'Content-Type': 'text/plain' }
});
}
}
// General API limit: 600 req/min per IP
const { ok, retryAfter } = checkRateLimit(`api:${ip}`, 600, 60_000);
if (!ok) {
return new Response('Too Many Requests', {