feat: default web API calls to same origin

This commit is contained in:
2026-05-01 08:35:06 +09:00
parent 7cfd50532d
commit 8656f237d4
7 changed files with 59 additions and 9 deletions

View File

@@ -1,6 +1,7 @@
JWT_SECRET=***
ENCRYPTION_SECRET=change-this-to-at-least-32-characters
JWT_SECRET=replace-me
ENCRYPTION_SECRET=replace-with-at-least-32-characters
DATABASE_URL=file:./dev.db
CODEXDASH_FRONTEND_ORIGIN=http://localhost:5173
CODEX_OAUTH_REDIRECT_URI=http://localhost:1455/auth/callback
# Optional: set this in local dev when the Vite app runs on a different origin than the API.
VITE_API_BASE_URL=http://localhost:3001

View File

@@ -73,8 +73,9 @@ docker run --rm \
Notes:
- The container serves the built React app from the same process on port `3001`.
- The bundled frontend defaults to `http://localhost:3001` for API calls. If you need a different origin, rebuild the image with `VITE_API_BASE_URL` set at build time.
- `CODEX_OAUTH_CALLBACK_BIND_HOST=0.0.0.0` is baked into the image so the callback bridge remains reachable through Docker port publishing while the public redirect URL can still stay on `localhost:1455`.
- The bundled frontend now defaults to the browser's current origin for API calls, so the production image can be deployed behind any host name without rebuilding the web bundle.
- `VITE_API_BASE_URL` is now optional and mainly useful for local development when Vite runs on a different origin than the API.
- `CODEX_OAUTH_CALLBACK_BIND_HOST=0.0.0.0` keeps the callback bridge reachable through Docker port publishing while the public redirect URL can still stay on `localhost:1455`.
- If the callback bridge is still unreachable in your setup, the manual callback URL paste fallback remains available.
## Environment variables
@@ -82,11 +83,12 @@ Notes:
### Root `.env`
```env
JWT_SECRET=***
ENCRYPTION_SECRET=***
JWT_SECRET=replace-me
ENCRYPTION_SECRET=replace-with-at-least-32-characters
DATABASE_URL=file:./dev.db
CODEXDASH_FRONTEND_ORIGIN=http://localhost:5173
CODEX_OAUTH_REDIRECT_URI=http://localhost:1455/auth/callback
# Optional in local dev when the web app does not share the API origin.
VITE_API_BASE_URL=http://localhost:3001
```

View File

@@ -7,7 +7,8 @@
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
"preview": "vite preview",
"test": "bun test ./test"
},
"dependencies": {
"@codexdash/shared-types": "workspace:*",

View File

@@ -0,0 +1,22 @@
const LOCALHOST_API_ORIGIN = 'http://localhost:3001';
function trimTrailingSlashes(value: string): string {
return value.replace(/\/+$/, '');
}
export function getApiBaseUrl(
configuredApiBaseUrl?: string,
windowOrigin?: string,
): string {
const configured = configuredApiBaseUrl?.trim();
if (configured) {
return trimTrailingSlashes(configured);
}
const origin = windowOrigin?.trim();
if (origin) {
return trimTrailingSlashes(origin);
}
return LOCALHOST_API_ORIGIN;
}

View File

@@ -10,9 +10,13 @@ import type {
UsageSummary,
UserProfile,
} from '@codexdash/shared-types';
import { getApiBaseUrl } from './api-base';
import { clearToken, getToken } from './storage';
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL ?? 'http://localhost:3001';
const API_BASE_URL = getApiBaseUrl(
import.meta.env.VITE_API_BASE_URL,
typeof window === 'undefined' ? undefined : window.location.origin,
);
async function request<T>(path: string, init?: RequestInit): Promise<T> {
const token = getToken();

View File

@@ -0,0 +1,20 @@
import { describe, expect, test } from 'bun:test';
import { getApiBaseUrl } from '../src/lib/api-base.ts';
describe('getApiBaseUrl', () => {
test('uses the configured API base when provided', () => {
expect(getApiBaseUrl('https://api.example.com/', 'https://app.example.com')).toBe(
'https://api.example.com',
);
});
test('defaults to the current window origin when no API base is configured', () => {
expect(getApiBaseUrl(undefined, 'https://app.example.com/')).toBe(
'https://app.example.com',
);
});
test('falls back to localhost in non-browser contexts without configuration', () => {
expect(getApiBaseUrl(undefined, undefined)).toBe('http://localhost:3001');
});
});

View File

@@ -21,7 +21,7 @@
"dev:web": "bun run --filter @codexdash/web dev",
"build": "bun run --filter @codexdash/api --filter @codexdash/web build",
"lint": "bun run --filter @codexdash/api --filter @codexdash/web lint",
"test": "bun run --filter @codexdash/api --if-present test",
"test": "bun run --filter @codexdash/api --filter @codexdash/web --if-present test",
"postinstall": "bun run --filter @codexdash/api prisma:generate"
}
}