Skip to content

fix(web): align no-.env API proxy fallback with server default#1159

Closed
LaplaceYoung wants to merge 1 commit intocoleam00:devfrom
LaplaceYoung:fix/windows-setup-env-port-1152
Closed

fix(web): align no-.env API proxy fallback with server default#1159
LaplaceYoung wants to merge 1 commit intocoleam00:devfrom
LaplaceYoung:fix/windows-setup-env-port-1152

Conversation

@LaplaceYoung
Copy link
Copy Markdown
Contributor

@LaplaceYoung LaplaceYoung commented Apr 13, 2026

Summary

  • fix the Vite dev proxy fallback to use the same default port as @archon/server (3000), so fresh installs without .env no longer proxy to :3090
  • centralize API port fallback logic in packages/web/src/lib/api-port.ts
  • add regression tests for undefined/blank/env-provided PORT resolution

Why

Issue #1152 reports a no-.env install path where server binds :3000 but Vite proxies /api to :3090, causing ECONNREFUSED and a broken web UI.

Testing

  • bun test packages/web/src/lib/api-port.test.ts
  • bun test packages/web/src/lib/

Closes #1152

Summary by CodeRabbit

  • Tests

    • Added test coverage for API port resolution logic.
  • Chores

    • Centralized API port configuration handling.
    • Default API port is now 3000.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 13, 2026

📝 Walkthrough

Walkthrough

A new utility module resolves the API port with a default of '3000' to match the server default, replacing the Vite config's hardcoded '3090' fallback. Tests verify the utility handles undefined, blank, and explicit port values correctly.

Changes

Cohort / File(s) Summary
API Port Utility
packages/web/src/lib/api-port.ts
New module exporting DEFAULT_API_PORT constant ('3000') and resolveApiPort() function that normalizes port input by trimming whitespace and returning the default when undefined or empty.
API Port Tests
packages/web/src/lib/api-port.test.ts
New Bun test file with three test cases covering undefined, blank, and explicit port string inputs to the resolveApiPort() function.
Vite Configuration
packages/web/vite.config.ts
Updated to import and use resolveApiPort(env.PORT) instead of the inline fallback env.PORT ?? '3090', changing the default proxy port from '3090' to '3000'.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A port that strayed from 3090 to '3000,
Now server and proxy sing in perfect tune!
Tests keep us honest, utilities stay clean,
The freshest installs are no longer a scene. 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description provides a summary with key points (problem, solution, test commands) and closes a linked issue, but lacks several required template sections like Architecture Diagram, Label Snapshot, Validation Evidence, Security Impact, and Rollback Plan. Add missing sections from the template: Architecture Diagram, Label Snapshot, Change Metadata, Validation Evidence (test results), Security Impact, Compatibility, Human Verification, and Rollback Plan.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and concisely describes the main change: aligning the Vite API proxy fallback port with the server default, which is the primary objective of this PR.
Linked Issues check ✅ Passed The PR fully implements objective #2 from issue #1152: aligning Vite's fallback port to 3000 to match the server default, with regression tests for undefined/blank/env-provided PORT resolution.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the linked issue #1152: new api-port module, tests, and Vite config update to align port defaults. No unrelated changes detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Copy Markdown

@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: 1

🧹 Nitpick comments (2)
packages/web/src/lib/api-port.ts (1)

1-1: Use DEFAULT_API_PORT as the single fallback source across web runtime code too.

There is still a hardcoded '3090' fallback in packages/web/src/lib/api.ts:15-21. Importing DEFAULT_API_PORT there would prevent future drift between Vite-time and runtime defaults.

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

In `@packages/web/src/lib/api-port.ts` at line 1, The codebase has a hardcoded
'3090' fallback in the runtime API URL code; import and use the exported
DEFAULT_API_PORT constant instead to keep a single source of truth. Modify the
module that constructs the runtime API port (the code currently falling back to
'3090') to import DEFAULT_API_PORT from the export (DEFAULT_API_PORT) and
replace the literal '3090' with that constant, ensuring any type conversion
(string vs number) remains correct when building the URL.
packages/web/src/lib/api-port.test.ts (1)

14-16: Add edge-case tests for trimming and invalid PORT values.

Please include a case for ' 3090 ' and (if validation is added) explicit throw assertions for invalid inputs like 'abc' and '70000' to lock behavior.

Proposed test additions
   test('uses PORT from env when provided', () => {
     expect(resolveApiPort('3090')).toBe('3090');
+    expect(resolveApiPort(' 3090 ')).toBe('3090');
   });
+
+  test('throws when PORT is invalid', () => {
+    expect(() => resolveApiPort('abc')).toThrow();
+    expect(() => resolveApiPort('70000')).toThrow();
+  });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/web/src/lib/api-port.test.ts` around lines 14 - 16, Add edge-case
tests for resolveApiPort: include a test asserting resolveApiPort(' 3090 ')
returns '3090' (trimming whitespace), and add tests for invalid inputs such as
'abc' and '70000' that assert the expected failure behavior (if you’ve
implemented validation, assert that resolveApiPort throws for those inputs;
otherwise assert the documented fallback behavior). Use descriptive test names
like "trims whitespace from PORT" and "throws on invalid PORT values" to make
intent clear and target the resolveApiPort function in the existing test file.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/web/src/lib/api-port.ts`:
- Around line 7-9: The resolveApiPort function currently returns any non-empty
string; modify it to validate and fail fast: trim the input (resolveApiPort), if
empty return DEFAULT_API_PORT; otherwise ensure the value matches /^\d+$/ then
parseInt(value,10) and assert the parsed port is between 1 and 65535; if
validation passes return the numeric port as a string, otherwise throw a clear
Error that includes the invalid port value (e.g., "Invalid API port: '<value>' —
must be an integer between 1 and 65535"), referencing resolveApiPort and
DEFAULT_API_PORT so callers can find and update behavior.

---

Nitpick comments:
In `@packages/web/src/lib/api-port.test.ts`:
- Around line 14-16: Add edge-case tests for resolveApiPort: include a test
asserting resolveApiPort(' 3090 ') returns '3090' (trimming whitespace), and add
tests for invalid inputs such as 'abc' and '70000' that assert the expected
failure behavior (if you’ve implemented validation, assert that resolveApiPort
throws for those inputs; otherwise assert the documented fallback behavior). Use
descriptive test names like "trims whitespace from PORT" and "throws on invalid
PORT values" to make intent clear and target the resolveApiPort function in the
existing test file.

In `@packages/web/src/lib/api-port.ts`:
- Line 1: The codebase has a hardcoded '3090' fallback in the runtime API URL
code; import and use the exported DEFAULT_API_PORT constant instead to keep a
single source of truth. Modify the module that constructs the runtime API port
(the code currently falling back to '3090') to import DEFAULT_API_PORT from the
export (DEFAULT_API_PORT) and replace the literal '3090' with that constant,
ensuring any type conversion (string vs number) remains correct when building
the URL.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1924d158-5aa6-434c-ae43-d1156468a6c2

📥 Commits

Reviewing files that changed from the base of the PR and between eb75ab6 and 12e3b59.

📒 Files selected for processing (3)
  • packages/web/src/lib/api-port.test.ts
  • packages/web/src/lib/api-port.ts
  • packages/web/vite.config.ts

Comment on lines +7 to +9
export function resolveApiPort(port: string | undefined): string {
const value = port?.trim();
return value ? value : DEFAULT_API_PORT;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validate PORT format/range and fail fast on invalid values.

resolveApiPort currently accepts any non-empty string. Values like abc or 70000 should throw a clear error instead of producing a broken proxy target at runtime.

Proposed fix
 export function resolveApiPort(port: string | undefined): string {
   const value = port?.trim();
-  return value ? value : DEFAULT_API_PORT;
+  if (!value) return DEFAULT_API_PORT;
+
+  const parsed = Number(value);
+  if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65535) {
+    throw new Error(`Invalid PORT value "${value}". Expected integer 1-65535.`);
+  }
+
+  return value;
 }
As per coding guidelines "Prefer throwing early with clear errors for unsupported/unsafe states rather than silently swallowing errors; never silently broaden permissions or capabilities (Fail Fast + Explicit Errors)".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/web/src/lib/api-port.ts` around lines 7 - 9, The resolveApiPort
function currently returns any non-empty string; modify it to validate and fail
fast: trim the input (resolveApiPort), if empty return DEFAULT_API_PORT;
otherwise ensure the value matches /^\d+$/ then parseInt(value,10) and assert
the parsed port is between 1 and 65535; if validation passes return the numeric
port as a string, otherwise throw a clear Error that includes the invalid port
value (e.g., "Invalid API port: '<value>' — must be an integer between 1 and
65535"), referencing resolveApiPort and DEFAULT_API_PORT so callers can find and
update behavior.

@leex279
Copy link
Copy Markdown
Collaborator

leex279 commented Apr 17, 2026

Hi @LaplaceYoung — thanks for working on this. Before this merges, I want to flag that I think this PR is based on the (reversed) RCA in issue #1152 and would actually introduce the bug the issue describes. Sharing verification so we can align.

The server does not default to 3000

packages/core/src/utils/port-allocation.ts on dev:

// line 33 (stale JSDoc — this is probably what misled the issue):
 * - Otherwise: use default 3000
...
// line 49 (actual code):
const basePort = 3090;

The JSDoc on line 33 is wrong; the real fallback is 3090. The default changed in #318 (Express → Hono migration); the comment was not updated.

I verified with a direct unit invocation (no PORT env var, no .env):

$ bun -e "delete process.env.PORT; const { getPort } = await import('./packages/core/src/utils/port-allocation.ts'); console.log(await getPort())"
3090

And Vite's loadEnv with no .env on disk:

$ bun -e "const { loadEnv } = await import('vite'); const env = loadEnv('development', process.cwd(), ''); console.log(env.PORT ?? '3090')"
3090

Both sides already default to 3090. Changing Vite's fallback to 3000 would create a real mismatch on fresh clones with no .env (server 3090, Vite 3000) — the exact scenario the issue claims breaks today.

The actual mismatch source

I wrote up the full analysis on the issue: #1152 (comment)

TL;DR — the mismatch isn't in code defaults; it comes from:

  1. .env.example:136 ships PORT=3000 (stale since Hono migration)
  2. packages/cli/src/commands/setup.ts:1293-1294 hardcodes PORT=3000 into generated .env files
  3. The Hono server also loads ~/.archon/.env with override: true, but Vite only reads repo-local .env — so if the wizard has written PORT=3000 to ~/.archon/.env without a matching repo-local .env, the two diverge

Alternative fix

I opened a PR taking the other direction — align .env.example, the setup wizard, and the stale JSDoc to the code's actual 3090 default (single source of truth in port-allocation.ts). Happy to close mine if we'd rather go with your direction, but I'd want to first update the server's basePort to 3000 as part of the change so the two ends genuinely match.

Let me know what makes sense to you and the maintainers.

@LaplaceYoung
Copy link
Copy Markdown
Contributor Author

Thank you for the detailed analysis! You're absolutely right. I'm honored that my PR could provide the inspiration for your deep dive into the root cause. I agree that aligning everything to the actual 3090 default, as you proposed in your PR, is likely the better direction. Let's see what the maintainers think, but I'm happy to follow your lead on this

@Wirasm
Copy link
Copy Markdown
Collaborator

Wirasm commented Apr 21, 2026

Thanks for looking at this, @LaplaceYoung — closing because the underlying issue is already resolved and this PR moves in the wrong direction.

What's actually on `dev`

Layer Default Source
Server 3090 `packages/core/src/utils/port-allocation.ts:49` (`basePort = 3090`)
Vite proxy 3090 `packages/web/vite.config.ts:11` (`env.PORT ?? '3090'`)

Server and Vite already match at 3090 when no `.env` exists. This PR would change the Vite fallback to 3000, introducing the very mismatch the original issue complained about (just in the opposite direction).

Why #1152's RCA was misleading

The original bug report asserted the server defaulted to 3000 and Vite to 3090. That was factually reversed — the server moved 3000 → 3090 in #318 (Hono migration) but `.env.example` and the setup wizard still documented/forced 3000. The real break case was:

  • Repo `.env` missing
  • `~/.archon/.env` has `PORT=3000` (left over from `archon setup` targeting a different project, or from an old wizard run)
  • Server loads both `.env` files → binds 3000
  • Vite only loads repo `.env` → proxies 3090 → `ECONNREFUSED`

@leex279 walked through this in the issue's closing comment: #1152

The actual fix already landed

#1271 (merged 2026-04-17) aligned everything on 3090:

  • Dropped hardcoded `PORT=3000` from `setup.ts` generated `.env`
  • Updated the wizard's "Additional Options" note to reflect 3090
  • Commented out `PORT=3090` in `.env.example` so it documents the default without forcing it

Single source of truth is now `port-allocation.ts:49`.

Salvageable parts

The `api-port.ts` centralization idea (trim blanks → fallback) is fine in principle, but without a port mismatch to fix there's no motivating behavior change — and the tests would lock in the wrong default. If there's a future need for a shared port helper, a separate PR using 3090 as the default would work.

Thanks again for digging in; this one just got fixed through a different angle before your PR surfaced.

@Wirasm Wirasm closed this Apr 21, 2026
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.

bug(setup): fresh install on Windows 11 leaves web UI broken — .env not created, server (:3000) and Vite proxy (:3090) default to different ports

3 participants