2025-10-10 23:04:50 -07:00
|
|
|
import { createRequestHandler } from "@react-router/express";
|
|
|
|
|
import express from "express";
|
2026-03-21 09:44:05 -07:00
|
|
|
import type { ServerBuild } from "react-router";
|
2025-10-11 20:56:00 -07:00
|
|
|
import { RouterContextProvider } from "react-router";
|
2025-10-10 23:04:50 -07:00
|
|
|
|
2025-10-24 21:20:19 -07:00
|
|
|
import { DatabaseContext } from "~/database/context";
|
Add CS2 Major Qualifying Points simulator and stage management (#260)
* Add CS2 Major qualifying points simulator
Implements a full CS2 Major tournament simulator with:
- 3-stage Swiss format (Opening Bo1, Elimination Bo1/Bo3, Decider all Bo3)
+ Champions Stage 8-team single-elimination (QF Bo3, SF Bo3, GF Bo5)
- Monte Carlo simulation (10,000 iterations) accumulating QP across 2 majors/season
- Sampled 24-team field per iteration: top 12 guaranteed, remaining weighted by 1/rank
- Stage 3 exits (placements 9-16) sub-ranked by W-L record (2-3 > 1-3 > 0-3)
- Stage assignments stored per-event so actual field composition drives simulation
- Admin CS Elo form for entering team Elo + HLTV world rankings
- Admin CS2 stage setup page for assigning teams to stages and tracking advancement
- Database migration: cs2_major_qualifying_points enum value + cs2_major_stage_results table
- 24 unit tests covering all exported pure functions
https://claude.ai/code/session_019w21Nkf5TvTZHH6oVHaQXR
* Consolidate Elo + ranking input into generic elo-ratings page
The darts-elo and cs-elo pages were unreachable from the admin nav,
which always links to the generic elo-ratings page. Extended elo-ratings
to conditionally show world ranking fields for simulator types that need
it (darts_bracket, cs2_major_qualifying_points), then deleted the
redundant sport-specific pages.
https://claude.ai/code/session_019w21Nkf5TvTZHH6oVHaQXR
* Consolidate server postgres connections into one shared pool
Four separate postgres() clients were open simultaneously (app, timer,
snapshots, socket), each defaulting to 10 connections, exhausting the
database's max_connections limit. Replaced with a single shared lazy-
initialized client in server/db.ts using a Proxy to defer the
DATABASE_URL check until first use (preserving test compatibility).
Also bumps the CS2 Champions Stage stochastic test from 200 → 1000
iterations to eliminate flakiness.
https://claude.ai/code/session_019w21Nkf5TvTZHH6oVHaQXR
* Fix and() bug and add Swiss loop safety guard
- cs2-major-stage.ts: markCs2StageEliminations and setCs2FinalPlacements
were using JS && instead of Drizzle and(), causing WHERE to filter only
by participantId (not scoringEventId), which would update rows across
all events instead of just the target event
- cs-major-simulator.ts: add break guard in simulateSwiss while loop to
prevent infinite loop if pairGroups returns no pairs
https://claude.ai/code/session_019w21Nkf5TvTZHH6oVHaQXR
* Fix all remaining code review issues
- cs2-major-stage.ts: use schema column reference for stageEliminated
in markCs2StageEliminations instead of raw SQL string
- cs-major-simulator.ts: simulateOneMajor now locks in known stage
results when a stage is complete (8 recorded eliminations), only
simulating the remaining stages during live events
- admin event page: add CS2 Stage Setup button for cs2_major_qualifying_points
simulator types; expose simulatorType in server loader type cast
- cs2-setup.tsx: replace document.getElementById DOM manipulation with
React state (eliminatedChecked map) for checkbox show/hide logic;
remove unused stageMap and unassignedParticipants variables
https://claude.ai/code/session_019w21Nkf5TvTZHH6oVHaQXR
* Fix oxlint errors: non-null assertions, sort→toSorted, unused vars
- cs-major-simulator.ts: replace 5 non-null assertions (!) with safe
optional chaining / if-guards; replace 6 .sort() with .toSorted()
- cs2-major-stage.ts: remove unused `inArray` import
- cs2-setup.tsx: remove unused `assignedIds` variable
https://claude.ai/code/session_019w21Nkf5TvTZHH6oVHaQXR
* Fix flaky Champions Stage stochastic test
The makeTeams(8) helper creates only a 70-pt Elo spread (1800→1730).
With the Champions Stage bracket math this gives team-0 a ~19.6% win
rate — right at the 0.2 threshold, causing the test to fail ~63% of
the time in CI despite 1000 iterations.
Use 100-pt steps (1800→1100) instead, giving team-0 a ~40% win rate
and raising the assertion threshold to 0.25 for a clear safety margin.
https://claude.ai/code/session_019w21Nkf5TvTZHH6oVHaQXR
---------
Co-authored-by: Claude <noreply@anthropic.com>
2026-04-05 13:40:05 -07:00
|
|
|
import { db } from "./db";
|
2025-10-24 21:20:19 -07:00
|
|
|
import { expressValueContext } from "~/contexts/express";
|
2025-10-10 23:04:50 -07:00
|
|
|
|
|
|
|
|
export const app = express();
|
|
|
|
|
|
|
|
|
|
app.use((_, __, next) => DatabaseContext.run(db, next));
|
|
|
|
|
|
2026-05-18 11:17:18 -07:00
|
|
|
// Block common bot probe paths before React Router (and Sentry) see them
|
|
|
|
|
const BOT_PROBE_RE =
|
|
|
|
|
/\.(php|env|htaccess|aspx|asp|jsp|config|bak|sql|ini|swp|DS_Store)$|^\/(wp-admin|wp-login|phpmyadmin|xmlrpc|server-status|cgi-bin|shell|cmd|console|actuator)(\/|$)/i;
|
|
|
|
|
|
|
|
|
|
app.use((req, res, next) => {
|
|
|
|
|
if (BOT_PROBE_RE.test(req.path)) {
|
|
|
|
|
res.status(404).end();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
next();
|
|
|
|
|
});
|
|
|
|
|
|
2025-10-10 23:04:50 -07:00
|
|
|
app.use(
|
|
|
|
|
createRequestHandler({
|
2026-03-21 09:44:05 -07:00
|
|
|
build: () => import("virtual:react-router/server-build") as unknown as Promise<ServerBuild>,
|
|
|
|
|
// @ts-ignore -- RouterContextProvider is the correct runtime type but tsconfig.server.json can't resolve the conditional type statically
|
2025-10-10 23:04:50 -07:00
|
|
|
getLoadContext() {
|
2025-10-16 18:15:04 -07:00
|
|
|
const provider = new RouterContextProvider();
|
|
|
|
|
provider.set(expressValueContext, "Hello from Express");
|
2026-03-21 09:44:05 -07:00
|
|
|
return provider as unknown as RouterContextProvider;
|
2025-10-10 23:04:50 -07:00
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
);
|