## 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:
Can't tell you how many times I've been playing solo, I try to go change
the speed from `Max` to `x1` and before I've opened the speed controls
and clicked on one the AI completely wipes me. But not to worry, we now
have a pause and speed toggle up/down keybinds!
https://github.com/user-attachments/assets/48692c27-888f-40fb-837a-45e26f262441
Keybinds were added to "Menu Shortcuts" submenu:
<img width="1750" height="1099" alt="image"
src="https://github.com/user-attachments/assets/8c4500d5-f43e-4a1c-9940-04db75bf18cf"
/>
Tested on Solo, custom match, and public lobbies. Pause intent works
correctly on solo and private match (only if you are host), and neither
feature works in public matches, as expected.
## 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:
bijx
## Description:
clientId replay bugfix (was picking first clientID in the array)
https://discord.com/channels/1359946986937258015/1479543573404844042
## 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:
- Removed all code related to generating a client ID on the client. The
server now assigns the client ID and sends it to the client in lobby
messages.
## 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:
https://github.com/user-attachments/assets/dc118d5f-3b7f-4ccb-8579-5b0d8c73fe8e
Catchup mechanic for live games and changes replays to have a backlog
for more "max" speed
## 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:
Describe the PR.
Modified FluentSlider(my code) to split number input handle to visual
update(NumberInput) and dispatch value(NumberComplete)
updated the event flow to match them, will fix rapid-fire updates that
seemed to glitch bots out.
## 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:
jackochess
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves#2491
## Description:
Adds pause/unpause functionality for private multiplayer games. Only the
lobby creator can pause the game, and all players see a pause overlay
when the game is paused.
**Key features:**
- Lobby creator sees pause/play button in control panel (alongside
existing singleplayer/replay controls)
- Server validates that only lobby creator can toggle pause
- All players see "Game paused by Lobby Creator" overlay when paused
- Game state freezes (no turn execution) while paused
- Unpause resumes normal gameplay
**Implementation details:**
- Server-side pause state (`isPaused`) prevents turn execution during
pause
- Each client receives `isLobbyCreator` flag in `GameStartInfo` to
show/hide pause button
- Added `TogglePauseIntent` that broadcasts to all clients via
`NoOpExecution`
- New `PauseOverlay` component (shows in single player also)
## 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:
furo18
<img width="1459" height="861" alt="Screenshot 2025-12-20 at 15 16 33"
src="https://github.com/user-attachments/assets/f5a3222f-f54b-473c-b0f6-104ce4c1e7a8"
/>
## Description:
The previous login system used long lived jwts which could be stolen by
XSS. The current system uses long lived refresh tokens that are stored
as http-only cookies. Then the client calls /refresh to get a short
lived jwt using the refresh token. The jwt is stored in memory only so
it's discarded on page close. This way a XSS can only steal the
short-lived jwt.
It also updates how accounts work: players get an account automatically
when they join the webpage. They can see their stats even if not logged
in. If a player wants to keep their account, they can tie it to their
Discord or email, allowing them to log in if cookies are lost.
## 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
#075c232 introduced a bug that prevented singplayer games from starting.
The `updateCallback` was not set for localserver, and local server
didn't send a start message when client sent a "rejoin".
## 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:
Finishes & closes#1969 and closes#1806.
## 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: Evan <evanpelle@gmail.com>
## Description:
This will be used to determine clan winners in the api layer.
## 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:
Cosmetics were not being saved into the GameRecord on game completion.
## 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:
Describe the PR.
## 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:
onunload allows up to 64kb, but reducing the number of hash messages and
compressing using gzip, we can reduce the GameRecord size to stay under
64kb. I played a 10 minute game and the compressed GameRecord was only a
few kb.
Also verify the game is singleplayer and has only 1 player
## 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:
The troop/worker ratio bar is almost never changed. so remove it and the
entire concept of workers. Now there is just troops.
Now players get a consistent 1k/s gold.
## 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
- [x] I have read and accepted the CLA agreement (only required once).
## Please put your Discord username so you can be contacted if a bug or
regression is found:
evan
## Description:
This contains the update from zod 3.25 to 4. Change imports back from
zod/v4 to just zod. No errors in VSCode.
## 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
- [x] I have read and accepted the CLA aggreement (only required once).
## Please put your Discord username so you can be contacted if a bug or
regression is found:
tryout33
## Description:
Add domain, subdomain to GameRecord.
## 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
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
Co-authored-by: evanpelle <evanpelle@gmail.com>
## Description:
- Expand the try/catch block in socket message handlers to encapsulate
all possible throwers.
- Remove unnecessary zod schema parsing of outgoing messages.
- Avoid unnecessary serialization and deserialization in singleplayer.
## 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
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
---------
Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
## Description:
Fixes#1232Fixes#1231
Add handle's
## 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
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
## Please put your Discord username so you can be contacted if a bug or
regression is found:
dovg
## Description:
updates zod to v4
closes#873
## 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
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
## Please put your Discord username so you can be contacted if a bug or
regression is found:
omrih
---------
Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
## Description:
PR for https://github.com/openfrontio/OpenFrontIO/issues/1105
This pull request introduces a new replay-panel under options-menu to
control singleplayer and replay speed.

User can select 4 different speed multipliers based on the
turnIntervalMs config.
I locally tested the feature in singleplayer mode. I couldn't find a way
to test replay mode.
Tested with the pause button, working as you would expect.
Here is an example:
[replay-speed.webm](https://github.com/user-attachments/assets/7b3a7616-5f8f-4fbb-88ba-0b2414c6f2ea)
## 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
⚠️ I need help to test this feature in real conditions with a replayed
game in dev env.
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
## Please put your Discord username so you can be contacted if a bug or
regression is found:
ghisloufou
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: evanpelle <evanpelle@gmail.com>
## Description:
Changed from consolex to console
## 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
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
## Please put your Discord username so you can be contacted if a bug or
regression is found:
@qqkedsi
## Description:
The LocalServer was counting 100ms between turns, causing the timer to
run slow (100ms + turn execution time), it now checks 100ms from the
start of the previous turn. I've noticed it still runs a tad slow (1-2
seconds slow after 1 minute), but it's much better than before.
## Please complete the following:
- [ ] I have added screenshots for all UI updates
- [ ] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [ ] I have added relevant tests to the test directory
- [ ] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [ ] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
## Please put your Discord username so you can be contacted if a bug or
regression is found:
<DISCORD USERNAME>
## Description:
- JSON serialization, bigint to string handling
- JSON deserialization, string to bigint handling
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
---------
Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
## Description:
Remove all references to playerID in the archive schema, since we
reference players by client id.
Also fixed the game not archiving bug, due to invalid reference.
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
## Please put your Discord username so you can be contacted if a bug or
regression is found:
<DISCORD USERNAME>
## Description:
Refactor various types across the project to use WinnerSchema.
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
## Description:
- Display "Checking login..." while waiting for the API server to
respond to our profile lookup request.
- Set the client to logged out if any of the API calls fail.
- Fix a bug causing the client to send a JWT even if the API server was
down.
Closes#824

## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
## Description:
Combine analytics and game types. Simplify and remove redundant player
information.
- Remove ip address.
- Add playerID.
- Combine redundant player tables.
- Move game metadata in to GameEndInfo type, an extension of
GameStartInfo
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
---------
Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
## Description:
Record player stats for the analytics worker to import in to to
postgres. This changes defines a new Analytics schema version, `v0.0.2`,
containing additional metadata about each player.
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
## Description:
Improve type safety and runtime correctness by:
1. Enabling TypeScript's
[strictNullChecks](https://www.typescriptlang.org/tsconfig/#strictNullChecks)
compiler option.
2. Replacing all loose equality operators (`==` and `!=`) with strict
equality operators (`===` and `!==`).
3. Cleaning up of type declarations, null handling logic, and equality
expressions throughout the project.
Currently, the code allows implicit assumptions that `null` and
`undefined` are interchangeable, and relies on type-coercing equality
checks that can introduce subtle bugs. These practices make it difficult
to reason about when values may be absent and hinder the effectiveness
of static analysis.
Migrating to strict null checks and enforcing strict equality
comparisons will clarify intent, reduce bugs, and make the codebase
safer and easier to maintain.
Fixes#466
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
---------
Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
Co-authored-by: evanpelle <openfrontio@gmail.com>
## Description:
This PR does two things:
1. Allow pausing on replay
2. As part of the refactoring, in singleplayer games, LocalServer now
waits for the last turn to complete execution before sending the next
turn. Previously, low end devices would sometimes fall behind getting
the "playing the past" bug where commands were delayed. Now when a
devices cannot keep up, the entire game slows down.
## Please complete the following:
- [ ] I have added screenshots for all UI updates
- [ ] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [ ] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
## Please put your Discord username so you can be contacted if a bug or
regression is found:
<DISCORD USERNAME>
Co-authored-by: evan <openfrontio@gmail.com>
## Description:
Remove the devils `clientID`, `persistentID`, and `gameID` from
`ClientBaseMessageSchema`, as well as `gameID` from `TurnSchema`. These
values are already known through the `Client` object that is hoisted
into the relevant handler.
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
---------
Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
## Description:
The server stores all players that have joined, and once the game starts
it sends a list of players to all clients. Players cannot join after the
game has started. Server now generated the PlayerID instead of the
client.
The is necessary for team mode, we need to know how who is playing the
game before it starts so we can properly assign teams based on clans.
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
## Please put your Discord username so you can be contacted if a bug or
regression is found:
evan
create endpoint to load archived game. when joining game client first
checks if the game is active, if not it requests the game archive from
the server. the archive is sent to LocalServer to replay the game
locally. Every 10 ticks a hash is stored on the archive, and during
replay the LocalServer verifies this hash.