6848fabce5 Improve Turnstile token handling with retry logic and timeouts (#4708)
**Add approved & assigned issue number here:**

Resolves #(issue number)

## Description:

Users intermittently saw **"Turnstile error: 600010"** immediately on a
fresh page load. The cause was the background token prefetch in
`initialize()`: on a cold visit Cloudflare occasionally returns a
transient `600xxx` challenge failure, and `getTurnstileToken()` reacted
to the very first error by tearing down the widget, rejecting, and
firing a blocking `alert()` — which also defeated Turnstile's own retry
and interrupted a user who hadn't even asked to play. On recent loads
Turnstile has cached session state and solves instantly, so the error
only showed on first load. (The JWT refresh flow is unrelated.)

Changes (`src/client/Main.ts`, plus one `en.json` string):

1. **Auto-retry instead of hard-fail** — added `retry: "auto"` +
`retry-interval` to the widget render, and the `error-callback` now
returns `true` (signalling "handled, retry") instead of removing the
widget and rejecting on the first blip. An overall 30s timeout
(`TURNSTILE_OVERALL_TIMEOUT_MS`) is the backstop so a token request can
never hang.
2. **Silent prefetch** — the background prefetch now swallows errors and
resolves `null`, so a cold-load blip no longer interrupts a user who
hasn't asked to play.
3. **Surface errors only at join time** — when a token genuinely can't
be obtained at the moment the user joins, they get an alert routed
through `translateText("turnstile.verification_failed")`, with the
string added to `en.json`.
4. **Type fix** — `turnstileTokenPromise` is now typed to reflect that
it can resolve to `null`.

### User impact

- The spurious first-load Turnstile alert is gone; transient Cloudflare
failures recover silently via retry.
- A clear, translated error message is shown only when verification
genuinely fails at join time.

## Please complete the following:

- [x] I have added screenshots for all UI updates <!-- no visual UI
changes; only an alert message that already exists -->
- [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 <!-- client
Turnstile path depends on the live window.turnstile widget and has no
unit harness; verified via tsc, ESLint, Prettier, and the existing
server-side turnstile tests -->

## Please put your Discord username so you can be contacted if a bug or
regression is found:

jish

---
🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-27 16:55:15 -07:00
2026-07-23 13:11:34 -07:00

OpenFrontIO Logo

OpenFront.io is an online real-time strategy game focused on territorial control and alliance building. Players compete to expand their territory, build structures, and form strategic alliances in various maps based on real-world geography.

This is a fork/rewrite of WarFront.io. Credit to https://github.com/WarFrontIO.

CI Crowdin CLA assistant License: AGPL v3 Assets: CC BY-SA 4.0

License

OpenFront source code is licensed under the GNU Affero General Public License v3.0

Current copyright notices appear in:

  • Footer: "© OpenFront and Contributors"
  • Loading screen: "© OpenFront and Contributors"

Modified versions must preserve these notices in reasonably visible locations.

See the LICENSE for complete requirements.

For asset licensing, see LICENSE-ASSETS.
For license history, see LICENSING.md.

🌟 Features

  • Real-time Strategy Gameplay: Expand your territory and engage in strategic battles
  • Alliance System: Form alliances with other players for mutual defense
  • Multiple Maps: Play across various geographical regions including Europe, Asia, Africa, and more
  • Resource Management: Balance your expansion with defensive capabilities
  • Cross-platform: Play in any modern web browser

📋 Prerequisites

  • npm (v10.9.2 or higher)
  • A modern web browser (Chrome, Firefox, Edge, etc.)

🚀 Installation

  1. Clone the repository

    git clone https://github.com/openfrontio/OpenFrontIO.git
    cd OpenFrontIO
    
  2. Install dependencies

    npm run inst
    

    Do NOT use npm install nor npm i but instead use our npm run inst. It runs the safer npm ci --ignore-scripts to install dependencies exactly according to the versions in package-lock.json and doesn't run scripts. This can prevent being hit by a supply chain attack.

🎮 Running the Game

Development Mode

Run both the client and server in development mode with live reloading:

npm run dev

This will:

  • Start the webpack dev server for the client
  • Launch the game server with development settings
  • Open the game in your default browser (to disable this behavior, set SKIP_BROWSER_OPEN=true in your environment)

Client Only

To run just the client with hot reloading:

npm run start:client

Server Only

To run just the server with development settings:

npm run start:server-dev

Connecting to staging or production backends

Sometimes it's useful to connect to production servers when replaying a game, testing user profiles, purchases, or login flow.

To replay a production game, make sure you're on the same commit that the game you want to replay was executed on, you can find the gitCommit value via https://api.openfront.io/game/[gameId]. Unfinished games cannot be replayed on localhost.

To connect to staging api servers:

npm run dev:staging

To connect to production api servers:

npm run dev:prod

🛠️ Development Tools

  • Format code:

    npm run format
    
  • Lint code:

    npm run lint
    
  • Lint and fix code:

    npm run lint:fix
    
  • Testing

    npm test
    

🏗️ Project Structure

  • /src/client - Frontend game client
  • /src/core - Deterministic game simulation
  • /src/server - Backend game server
  • /resources - Static assets (images, maps, etc.)

🤝 Contributing

Contributions and translations are welcome! See CONTRIBUTING.md for the workflow, the approved-issue process, project governance, and translation info.

S
Description
No description provided
Readme AGPL-3.0
1,020 MiB
Languages
TypeScript 91.4%
GLSL 2.5%
JavaScript 2%
HTML 1.5%
Go 1%
Other 1.5%