Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/core/configuration/ConfigLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,18 @@ export async function getServerConfigFromClient(): Promise<ServerConfig> {
return cachedSC;
}

const bootstrapGameEnv = window.BOOTSTRAP_CONFIG?.gameEnv;
if (!bootstrapGameEnv) {
throw new Error("Missing bootstrap server config");
const bootstrapGameEnv =
typeof window !== "undefined"
? window.BOOTSTRAP_CONFIG?.gameEnv
: undefined;
// Vite replaces this at build time for browser and worker bundles.
const bundledGameEnv = process.env.GAME_ENV;
const gameEnv = bootstrapGameEnv ?? bundledGameEnv;
if (!gameEnv) {
throw new Error("Missing client server config");
}

cachedSC = getServerConfig(bootstrapGameEnv);
cachedSC = getServerConfig(gameEnv);
Comment on lines +42 to +53
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Inspecting client env resolution branch in ConfigLoader:"
rg -n -C3 'bootstrapGameEnv|bundledGameEnv|gameEnv =|typeof window' src/core/configuration/ConfigLoader.ts

echo
echo "Inspecting Vite define mapping for process.env.GAME_ENV:"
rg -n -C3 '"process.env.GAME_ENV"' vite.config.ts

Repository: openfrontio/OpenFrontIO

Length of output: 1154


Restrict bundled environment fallback to worker runtimes only.

At line 48, bootstrapGameEnv ?? bundledGameEnv falls back to build-time config even in browser contexts when bootstrap is missing. This masks bootstrap failures and can route staging/test environments to the production build-time value.

Suggested fix
-  const bootstrapGameEnv =
-    typeof window !== "undefined"
-      ? window.BOOTSTRAP_CONFIG?.gameEnv
-      : undefined;
-  // Vite replaces this at build time for browser and worker bundles.
-  const bundledGameEnv = process.env.GAME_ENV;
-  const gameEnv = bootstrapGameEnv ?? bundledGameEnv;
+  const gameEnv =
+    typeof window !== "undefined"
+      ? window.BOOTSTRAP_CONFIG?.gameEnv
+      : process.env.GAME_ENV; // worker / non-window runtime
   if (!gameEnv) {
     throw new Error("Missing client server config");
   }

This ensures browsers always use runtime bootstrap config and only workers fall back to the build-time environment variable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/configuration/ConfigLoader.ts` around lines 42 - 53, The code
currently uses bootstrapGameEnv ?? bundledGameEnv for gameEnv which allows the
build-time bundledGameEnv to be used in browser contexts when bootstrap is
missing; change the logic so browsers (typeof window !== "undefined") always use
bootstrapGameEnv only, and only non-browser runtimes (workers/Node) fall back to
bundledGameEnv. Update the assignment for gameEnv to prefer bootstrapGameEnv in
browser contexts and to use bootstrapGameEnv ?? bundledGameEnv when window is
undefined, then continue to call getServerConfig(gameEnv) and assign cachedSC as
before (references: bootstrapGameEnv, bundledGameEnv, gameEnv, getServerConfig,
cachedSC).

return cachedSC;
}
export function getServerConfigFromServer(): ServerConfig {
Expand Down
11 changes: 11 additions & 0 deletions tests/core/configuration/ConfigLoader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import {
} from "../../../src/core/configuration/ConfigLoader";

describe("ConfigLoader", () => {
const originalGameEnv = process.env.GAME_ENV;

beforeEach(() => {
vi.restoreAllMocks();
window.BOOTSTRAP_CONFIG = undefined;
process.env.GAME_ENV = originalGameEnv;
clearCachedServerConfig();
});

Expand All @@ -21,4 +24,12 @@ describe("ConfigLoader", () => {
expect(config.env()).toBe(GameEnv.Prod);
expect(fetchSpy).not.toHaveBeenCalled();
});

test("falls back to bundled env when bootstrap config is unavailable", async () => {
process.env.GAME_ENV = "prod";

const config = await getServerConfigFromClient();

expect(config.env()).toBe(GameEnv.Prod);
});
});
Loading