Skip to content

Conversation

@evanpelle
Copy link
Collaborator

If this PR fixes an issue, link it below. If not, delete these two lines.
Resolves #(issue number)

Description:

Describe the PR.

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

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

DISCORD_USERNAME

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 7, 2026

Walkthrough

The PR transitions server configuration delivery from a runtime HTTP API fetch to build-time injection into the global window.SERVER_CONFIG object. The /api/env endpoint and its nginx caching rules are removed. Configuration getters now read the injected global object, with fallback to environment variables.

Changes

Cohort / File(s) Summary
Build & Environment Setup
.vscode/settings.json, vite.config.ts
Disables HTML script validation; injects serverConfig JSON with GAME_ENV and NUM_WORKERS into Vite template data for build-time injection
HTML Entry Point
index.html
Adds script block that assigns window.SERVER_CONFIG from injected serverConfig before the CrazyGames SDK loads
Client Configuration Layer
src/client/ServerConfig.ts
New module exports ServerConfig interface and getServerConfig() function for consuming the injected global config with runtime validation
Environment & Config Resolution
src/core/configuration/Env.ts, src/core/configuration/ConfigLoader.ts
Updates getters to prioritize window.SERVER_CONFIG before falling back to import.meta.env and process.env; adds global Window type declaration
Server API
src/server/Master.ts
Removes the /api/env HTTP endpoint that previously returned GAME_ENV
Infrastructure
nginx.conf
Removes /api/env location block and its 1-hour cache configuration

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Allow NUM_WORKERS override #2776: Both PRs modify how the application handles NUM_WORKERS—this PR injects it into window.SERVER_CONFIG, while the related PR adds server-side validation and environment-variable handling.

Suggested labels

Devops

Poem

📦 Config moves from the wire to build-time light,
Global scope holds secrets, injected just right,
No HTTP dance at runtime's dawn,
One window.SERVER_CONFIG to carry on! 🌍

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description contains only a default PR template with placeholders and no actual implementation details related to the changeset. Replace the template with a meaningful description of the changes, including why environment variables are being passed to the client and what benefits this provides.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main changes: passing environment variables to the client via index.html and removing the /api/env endpoint.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In @src/core/configuration/Env.ts:
- Line 55: The comment in Env.ts that currently says "injected at build time" is
inaccurate; update the two occurrences (the comment above the check for
window.SERVER_CONFIG at the lines around 55 and 108) to state that
window.SERVER_CONFIG is injected at runtime (when the HTML is served) or
"injected into index.html at runtime", so the comment accurately reflects the
runtime injection behavior shown in index.html/vite.config.ts.
- Around line 55-62: The code returns window.SERVER_CONFIG.gameEnv even when
it's empty/falsy, preventing fallback to import.meta.env.MODE or
process.env.GAME_ENV; update the getter in Env (the block that checks
window.SERVER_CONFIG and accesses gameEnv) to verify that
window.SERVER_CONFIG.gameEnv is a non-empty/truthy string before returning it
(e.g., check typeof and truthiness), and only return it when valid so that
otherwise the function proceeds to the existing fallbacks.
- Around line 108-115: The current check returns
String(window.SERVER_CONFIG.numWorkers) unconditionally which yields "undefined"
when numWorkers is missing; instead read the value into a variable (e.g., const
numWorkers = window.SERVER_CONFIG.numWorkers), verify it is not null or
undefined (numWorkers !== undefined && numWorkers !== null) before returning
String(numWorkers), and only fall back to getEnv("NUM_WORKERS") when that
validation fails; update the logic around window.SERVER_CONFIG.numWorkers in
Env.ts accordingly.

In @vite.config.ts:
- Around line 59-62: Update the serverConfig JSON.stringify block in
vite.config.ts to validate and sanitize NUM_WORKERS and to include "staging" in
the gameEnv fallback: parse env.NUM_WORKERS to an integer, check for NaN and
clamp to a minimum of 1 (default to 2 if invalid), then use that sanitized value
for numWorkers; for gameEnv, prefer env.GAME_ENV if present, otherwise compute a
fallback that checks isProduction first, then an isStaging flag (compute
isStaging similar to isProduction or via env.NODE_ENV/other config), returning
"staging" if set, else "dev"; reference the existing serverConfig construction,
env.NUM_WORKERS, parseInt usage, and gameEnv/isProduction symbols when making
the changes.
🧹 Nitpick comments (2)
src/core/configuration/ConfigLoader.ts (1)

36-47: Consider renaming to reduce confusion.

The code correctly reads from window.SERVER_CONFIG, but there are naming overlaps that could confuse developers:

  1. ServerConfig interface in client/ServerConfig.ts (raw window data) vs ServerConfig type in Config.ts (configuration logic)
  2. getServerConfig() in client/ServerConfig.ts vs getServerConfig(gameEnv) in this file (different signatures)

While technically correct, consider renaming the raw interface to something like InjectedServerConfig or ServerConfigData to clarify the distinction.

src/client/ServerConfig.ts (1)

8-21: Implementation is clean and correct.

The interface and getter function are straightforward. The error handling properly checks for missing window.SERVER_CONFIG.

As noted in ConfigLoader.ts, consider renaming this interface (e.g., InjectedServerConfig) to distinguish it from the ServerConfig type imported from Config.ts. This would make the codebase clearer for developers encountering both types.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3cd2274 and 954d674.

📒 Files selected for processing (8)
  • .vscode/settings.json
  • index.html
  • nginx.conf
  • src/client/ServerConfig.ts
  • src/core/configuration/ConfigLoader.ts
  • src/core/configuration/Env.ts
  • src/server/Master.ts
  • vite.config.ts
💤 Files with no reviewable changes (2)
  • nginx.conf
  • src/server/Master.ts
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-12-29T23:33:17.920Z
Learnt from: wraith4081
Repo: openfrontio/OpenFrontIO PR: 2735
File: index.html:390-391
Timestamp: 2025-12-29T23:33:17.920Z
Learning: In Tailwind CSS v4, update blur-related utilities in HTML templates. The mappings are: backdrop-blur-sm (v3) -> backdrop-blur-xs (v4); backdrop-blur (bare) -> backdrop-blur-sm; blur-sm -> blur-xs. Apply these changes to all HTML files (e.g., index.html and other templates) to reflect the v4 naming. Consider updating a project-wide search/replace or using a codemod to ensure consistency across the codebase.

Applied to files:

  • index.html
📚 Learning: 2025-11-12T23:11:34.445Z
Learnt from: MaxHT0x
Repo: openfrontio/OpenFrontIO PR: 2262
File: src/core/configuration/DefaultConfig.ts:806-832
Timestamp: 2025-11-12T23:11:34.445Z
Learning: In src/core/configuration/DefaultConfig.ts, JSDoc documentation for configuration methods should not be added inline, as it was requested that documentation be placed elsewhere in the codebase.

Applied to files:

  • src/core/configuration/ConfigLoader.ts
🧬 Code graph analysis (2)
src/client/ServerConfig.ts (1)
src/core/configuration/ConfigLoader.ts (1)
  • getServerConfig (53-67)
src/core/configuration/ConfigLoader.ts (1)
src/client/ServerConfig.ts (1)
  • getServerConfig (17-22)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Deploy to openfront.dev
🔇 Additional comments (3)
.vscode/settings.json (1)

1-3: Dev setting looks good.

Disabling HTML script validation makes sense given the runtime-injected window.SERVER_CONFIG script in index.html. This prevents false positives during development.

index.html (1)

136-139: Global config injection looks correct.

The window.SERVER_CONFIG assignment uses unescaped EJS (<%-), which is safe here because serverConfig is already JSON.stringify'd in vite.config.ts. The placement before the CrazyGames SDK ensures the config is available when needed.

src/core/configuration/ConfigLoader.ts (1)

9-10: Side-effect import for type declaration.

This import ensures the global Window interface extension (with SERVER_CONFIG property) is available. While this pattern works, it relies on implicit side effects.

Comment on lines +14 to +19
interface Window {
SERVER_CONFIG?: {
gameEnv: string;
numWorkers: number;
};
}
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

Type mismatch: numWorkers should be string or the getter should return number.

The interface defines numWorkers: number, but the NUM_WORKERS getter (line 111) converts it to a string with String(window.SERVER_CONFIG.numWorkers). This creates type confusion.

Either change the interface to numWorkers: string or have the getter return the number directly without conversion.

Proposed fix: align types

Option 1 - Make interface use string:

  interface Window {
    SERVER_CONFIG?: {
      gameEnv: string;
-      numWorkers: number;
+      numWorkers: string;
    };
  }

Option 2 - Return number from getter:

  get NUM_WORKERS() {
    // Check window.SERVER_CONFIG first (injected at build time)
    try {
      if (typeof window !== "undefined" && window.SERVER_CONFIG) {
-        return String(window.SERVER_CONFIG.numWorkers);
+        return window.SERVER_CONFIG.numWorkers;
      }
    } catch {
      // Ignore errors accessing window
    }

    return getEnv("NUM_WORKERS");
  },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
interface Window {
SERVER_CONFIG?: {
gameEnv: string;
numWorkers: number;
};
}
interface Window {
SERVER_CONFIG?: {
gameEnv: string;
numWorkers: string;
};
}


export const Env = {
get GAME_ENV(): string {
// Check window.SERVER_CONFIG first (injected at build time)
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 | 🟡 Minor

Comment says "build time" but injection appears to be at runtime.

The comments state "injected at build time", but based on the PR context (index.html and vite.config.ts), the window.SERVER_CONFIG object is injected at runtime when the HTML is served, not during the build process.

Update the comment for accuracy:

-    // Check window.SERVER_CONFIG first (injected at build time)
+    // Check window.SERVER_CONFIG first (injected at runtime)

Also applies to: 108-108

🤖 Prompt for AI Agents
In @src/core/configuration/Env.ts at line 55, The comment in Env.ts that
currently says "injected at build time" is inaccurate; update the two
occurrences (the comment above the check for window.SERVER_CONFIG at the lines
around 55 and 108) to state that window.SERVER_CONFIG is injected at runtime
(when the HTML is served) or "injected into index.html at runtime", so the
comment accurately reflects the runtime injection behavior shown in
index.html/vite.config.ts.

Comment on lines +55 to +62
// Check window.SERVER_CONFIG first (injected at build time)
try {
if (typeof window !== "undefined" && window.SERVER_CONFIG) {
return window.SERVER_CONFIG.gameEnv;
}
} catch {
// Ignore errors accessing window
}
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

Fallback won't trigger if gameEnv is empty or falsy.

If window.SERVER_CONFIG exists but gameEnv is an empty string or other falsy value, the getter returns that falsy value instead of falling back to import.meta.env.MODE or process.env.GAME_ENV.

Consider checking if the value is truthy before returning it:

Proposed fix
  // Check window.SERVER_CONFIG first (injected at build time)
  try {
    if (typeof window !== "undefined" && window.SERVER_CONFIG) {
-      return window.SERVER_CONFIG.gameEnv;
+      const gameEnv = window.SERVER_CONFIG.gameEnv;
+      if (gameEnv) {
+        return gameEnv;
+      }
    }
  } catch {
    // Ignore errors accessing window
  }
🤖 Prompt for AI Agents
In @src/core/configuration/Env.ts around lines 55 - 62, The code returns
window.SERVER_CONFIG.gameEnv even when it's empty/falsy, preventing fallback to
import.meta.env.MODE or process.env.GAME_ENV; update the getter in Env (the
block that checks window.SERVER_CONFIG and accesses gameEnv) to verify that
window.SERVER_CONFIG.gameEnv is a non-empty/truthy string before returning it
(e.g., check typeof and truthiness), and only return it when valid so that
otherwise the function proceeds to the existing fallbacks.

Comment on lines +108 to +115
// Check window.SERVER_CONFIG first (injected at build time)
try {
if (typeof window !== "undefined" && window.SERVER_CONFIG) {
return String(window.SERVER_CONFIG.numWorkers);
}
} catch {
// Ignore errors accessing window
}
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

Fallback won't trigger if numWorkers is missing or 0.

If window.SERVER_CONFIG exists but numWorkers is undefined or 0, the behavior is problematic:

  • String(undefined) returns "undefined" as a string literal
  • String(0) returns "0", which might be valid but prevents fallback to getEnv("NUM_WORKERS")

Check if the value exists and is valid before returning it:

Proposed fix
  // Check window.SERVER_CONFIG first (injected at build time)
  try {
    if (typeof window !== "undefined" && window.SERVER_CONFIG) {
-      return String(window.SERVER_CONFIG.numWorkers);
+      const numWorkers = window.SERVER_CONFIG.numWorkers;
+      if (numWorkers !== undefined && numWorkers !== null) {
+        return String(numWorkers);
+      }
    }
  } catch {
    // Ignore errors accessing window
  }
🤖 Prompt for AI Agents
In @src/core/configuration/Env.ts around lines 108 - 115, The current check
returns String(window.SERVER_CONFIG.numWorkers) unconditionally which yields
"undefined" when numWorkers is missing; instead read the value into a variable
(e.g., const numWorkers = window.SERVER_CONFIG.numWorkers), verify it is not
null or undefined (numWorkers !== undefined && numWorkers !== null) before
returning String(numWorkers), and only fall back to getEnv("NUM_WORKERS") when
that validation fails; update the logic around window.SERVER_CONFIG.numWorkers
in Env.ts accordingly.

Comment on lines +59 to +62
serverConfig: JSON.stringify({
gameEnv: env.GAME_ENV || (isProduction ? "prod" : "dev"),
numWorkers: parseInt(env.NUM_WORKERS || "2", 10),
}),
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

Handle invalid NUM_WORKERS input.

The parseInt call will return NaN if NUM_WORKERS is set to a non-numeric value. This could cause runtime issues. Add validation or use a safer default.

Additionally, the gameEnv fallback logic doesn't account for "staging", which is a valid option in ConfigLoader.ts (line 58). Consider adding it to the fallback.

🛡️ Proposed fix with validation
           data: {
             serverConfig: JSON.stringify({
-              gameEnv: env.GAME_ENV || (isProduction ? "prod" : "dev"),
-              numWorkers: parseInt(env.NUM_WORKERS || "2", 10),
+              gameEnv: env.GAME_ENV || (isProduction ? "prod" : "dev"),
+              numWorkers: Math.max(1, parseInt(env.NUM_WORKERS || "2", 10) || 2),
             }),
           },

This ensures:

  • If NUM_WORKERS is invalid, defaults to 2
  • If it's valid but less than 1, clamps to 1
🤖 Prompt for AI Agents
In @vite.config.ts around lines 59 - 62, Update the serverConfig JSON.stringify
block in vite.config.ts to validate and sanitize NUM_WORKERS and to include
"staging" in the gameEnv fallback: parse env.NUM_WORKERS to an integer, check
for NaN and clamp to a minimum of 1 (default to 2 if invalid), then use that
sanitized value for numWorkers; for gameEnv, prefer env.GAME_ENV if present,
otherwise compute a fallback that checks isProduction first, then an isStaging
flag (compute isStaging similar to isProduction or via env.NODE_ENV/other
config), returning "staging" if set, else "dev"; reference the existing
serverConfig construction, env.NUM_WORKERS, parseInt usage, and
gameEnv/isProduction symbols when making the changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants