## Description:
This is a refactor to simplify config handling.
Replaces the per-environment DevConfig/PreprodConfig/ProdConfig class
hierarchy with two static classes: ClientEnv (browser main thread, reads
from window.BOOTSTRAP_CONFIG) and ServerEnv (Node server, reads from
process.env). The four config classes are deleted, the abstract
DefaultServerConfig is gone, and DefaultConfig is renamed to Config.
The values that flow server → client (gameEnv, numWorkers,
turnstileSiteKey, jwtAudience, instanceId) used to be baked into the
hardcoded per-env classes. They're now real env vars on the server,
embedded into a single window.BOOTSTRAP_CONFIG object in index.html at
request time (alongside the existing gitCommit/assetManifest/cdnBase
globals, which moved into the same object), and read back by ClientEnv
on the client. The dev defaults previously hidden inside DevServerConfig
are now explicit in start:server-dev (NUM_WORKERS=2,
TURNSTILE_SITE_KEY=1x..., JWT_AUDIENCE=localhost, etc.) and in
vite.config.ts's html plugin inject.data. Production deploys plumb
NUM_WORKERS and TURNSTILE_SITE_KEY through deploy.yml (GitHub vars) into
the remote env file; JWT_AUDIENCE is derived from DOMAIN in deploy.sh.
The dynamic /api/instance endpoint is gone — INSTANCE_ID rides along in
BOOTSTRAP_CONFIG now.
ServerEnv is the only thing server code touches; ClientEnv is
browser-only. The two classes have intentional overlap (env, numWorkers,
jwtIssuer, gameCreationRate, workerIndex, etc.) since they derive
identical logic from different sources — there's a TODO in each to
consolidate via a shared helper later. The game-logic Config no longer
stores a ServerConfig/ClientEnv reference and its serverConfig() getter
is gone; the one caller (MultiTabModal) now reads ClientEnv.env()
directly. Worker init no longer carries server-config values since
nothing in the worker actually reads them.
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
evan
## Description:
improvements to clan ui.
<img width="788" height="290" alt="image"
src="https://github.com/user-attachments/assets/736ca147-bff4-44d8-8180-7b80a85556fe"
/>
added "expand all" and new collapsible sections.
<img width="787" height="550" alt="image"
src="https://github.com/user-attachments/assets/deb2f813-854b-46a9-a767-52c4f749f30f"
/>
which changes to collapse all when expanded
also adds more info about team (d,t,q,2,3,4,5,6,7 team)
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
w.o.n
## Description:
Continuation from #3276
Adds the complete client-side clan UI as a Lit web component
(`<clan-modal>`), a typed API client with Zod-validated responses,
shared response schemas, and a reusable `<confirm-dialog>` component.
### New: `ClanModal.ts`
| View | What it does |
|------|-------------|
| **My Clans** | Lists joined clans + pending join requests (built from
`/users/@me`, no extra fetches) |
| **Browse** | Search by tag (min 3 chars), paginated results,
configurable per-page (10/25/50) |
| **Clan Detail** | Stats, paginated + searchable member list, role
badges, join/leave/request actions |
| **Manage** | Edit name (max 35 chars) + description, toggle
open/invite-only, disband |
| **Transfer** | Leadership transfer with member selector + confirmation
|
| **Requests** | Approve/deny join requests (leader/officer) |
| **Bans** | View and unban (leader/officer) |
| **My Requests** | View and withdraw outgoing requests |
### New: `ConfirmDialog.ts`
Reusable `<confirm-dialog>` Lit component — replaces native
`confirm()`/`prompt()` which are blocked or broken on mobile and
CrazyGames iframes. Supports danger/warning variants and an optional
textarea (used for ban reasons). Fires `confirm`/`cancel` events.
### New: `ClanApi.ts`
Typed API client covering all clan endpoints. Every response is
Zod-validated. Auth header is always last in the spread (can't be
overridden by callers). Unknown server error messages always fall back
to a generic client-side string — never displayed verbatim.
### New: `ClanApiSchemas.ts` (in `src/core/`)
Shared Zod schemas for clan API responses with max-length constraints on
`name` (35) and `description` (200). Lives in `core/` so it can be
consumed by both client code and the leaderboard table.
### Modified: `ApiSchemas.ts`
- Added `clans` and `clanRequests` arrays to `UserMeResponseSchema`
- Moved clan leaderboard schemas out to `ClanApiSchemas.ts`
- Renamed `LeaderboardClanTagSchema` → `RequiredClanTagSchema`
### Modified: `Api.ts`
- Added `invalidateUserMe()` to bust the cached `/users/me` response
after mutations
- Removed `fetchClanLeaderboard` (moved to `ClanApi.ts`)
### Tests
- `ClanModal.test.ts` — rendering, view navigation, user actions
- `ClanApiQueries.test.ts` — fetch functions, error handling, pagination
- `ClanApiMutations.test.ts` — join, leave, kick, ban, promote,
transfer, etc.
- `ClanApiBans.test.ts` — ban/unban calls and error paths
- `ClanApiSchemas.test.ts` — Zod schema validation edge cases
- `LeaderboardModal.test.ts` — updated imports
## Notable design decisions
- **Not-logged-in state** — shows "Sign in to join clans" instead of
false "no clans" empty state
- **Rate limit feedback** — reads `Retry-After` header and surfaces wait
time to the user
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
w.o.n
---------
Co-authored-by: evanpelle <evanpelle@gmail.com>