mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-29 15:15:27 -07:00
Fix web API URL for remote access (#550)
Default production web builds to the page origin so Docker and LAN users do not fetch from browser-local localhost. Preserve the local/Tauri fallback and repair stale persisted loopback URLs.
This commit is contained in:
+10
-1
@@ -11,7 +11,11 @@ import { cn } from '@/lib/utils/cn';
|
|||||||
import { usePlatform } from '@/platform/PlatformContext';
|
import { usePlatform } from '@/platform/PlatformContext';
|
||||||
import { router } from '@/router';
|
import { router } from '@/router';
|
||||||
import { useLogStore } from '@/stores/logStore';
|
import { useLogStore } from '@/stores/logStore';
|
||||||
import { useServerStore } from '@/stores/serverStore';
|
import {
|
||||||
|
getDefaultServerUrl,
|
||||||
|
isLoopbackVoiceboxServerUrl,
|
||||||
|
useServerStore,
|
||||||
|
} from '@/stores/serverStore';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate that a health response has the expected Voicebox-specific shape.
|
* Validate that a health response has the expected Voicebox-specific shape.
|
||||||
@@ -105,6 +109,11 @@ function App() {
|
|||||||
// Setup window close handler and auto-start server when running in Tauri (production only)
|
// Setup window close handler and auto-start server when running in Tauri (production only)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!platform.metadata.isTauri) {
|
if (!platform.metadata.isTauri) {
|
||||||
|
const serverUrl = getDefaultServerUrl();
|
||||||
|
const currentServerUrl = useServerStore.getState().serverUrl;
|
||||||
|
if (currentServerUrl !== serverUrl && isLoopbackVoiceboxServerUrl(currentServerUrl)) {
|
||||||
|
useServerStore.getState().setServerUrl(serverUrl);
|
||||||
|
}
|
||||||
setServerReady(true); // Web assumes server is running
|
setServerReady(true); // Web assumes server is running
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,44 @@ function invalidateAllServerData() {
|
|||||||
queryClient.invalidateQueries();
|
queryClient.invalidateQueries();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getDefaultServerUrl(): string {
|
||||||
|
const fallback = 'http://127.0.0.1:17493';
|
||||||
|
|
||||||
|
if (!import.meta.env.PROD || typeof window === 'undefined') {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { protocol, origin, hostname } = window.location;
|
||||||
|
if (
|
||||||
|
(protocol === 'http:' || protocol === 'https:') &&
|
||||||
|
origin &&
|
||||||
|
hostname !== 'tauri.localhost'
|
||||||
|
) {
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isLoopbackVoiceboxServerUrl(url: string): boolean {
|
||||||
|
try {
|
||||||
|
const parsed = new URL(url);
|
||||||
|
return (
|
||||||
|
parsed.port === '17493' &&
|
||||||
|
(parsed.hostname === '127.0.0.1' ||
|
||||||
|
parsed.hostname === 'localhost' ||
|
||||||
|
parsed.hostname === '[::1]' ||
|
||||||
|
parsed.hostname === '::1')
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const useServerStore = create<ServerStore>()(
|
export const useServerStore = create<ServerStore>()(
|
||||||
persist(
|
persist(
|
||||||
(set, get) => ({
|
(set, get) => ({
|
||||||
serverUrl: 'http://127.0.0.1:17493',
|
serverUrl: getDefaultServerUrl(),
|
||||||
setServerUrl: (url) => {
|
setServerUrl: (url) => {
|
||||||
const prev = get().serverUrl;
|
const prev = get().serverUrl;
|
||||||
set({ serverUrl: url });
|
set({ serverUrl: url });
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import type { PlatformLifecycle, ServerLogEntry } from '@/platform/types';
|
import type { PlatformLifecycle, ServerLogEntry } from '@/platform/types';
|
||||||
|
import { getDefaultServerUrl } from '@/stores/serverStore';
|
||||||
|
|
||||||
class WebLifecycle implements PlatformLifecycle {
|
class WebLifecycle implements PlatformLifecycle {
|
||||||
onServerReady?: () => void;
|
onServerReady?: () => void;
|
||||||
|
|
||||||
async startServer(_remote = false, _modelsDir?: string | null): Promise<string> {
|
async startServer(_remote = false, _modelsDir?: string | null): Promise<string> {
|
||||||
// Web assumes server is running externally
|
// Web assumes server is running externally
|
||||||
// Return a default URL - this should be configured via env vars
|
const serverUrl = import.meta.env.VITE_SERVER_URL || getDefaultServerUrl();
|
||||||
const serverUrl = import.meta.env.VITE_SERVER_URL || 'http://localhost:17493';
|
|
||||||
this.onServerReady?.();
|
this.onServerReady?.();
|
||||||
return serverUrl;
|
return serverUrl;
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ class WebLifecycle implements PlatformLifecycle {
|
|||||||
|
|
||||||
async restartServer(_modelsDir?: string | null): Promise<string> {
|
async restartServer(_modelsDir?: string | null): Promise<string> {
|
||||||
// No-op for web - server is managed externally
|
// No-op for web - server is managed externally
|
||||||
return import.meta.env.VITE_SERVER_URL || 'http://localhost:17493';
|
return import.meta.env.VITE_SERVER_URL || getDefaultServerUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
async setKeepServerRunning(_keep: boolean): Promise<void> {
|
async setKeepServerRunning(_keep: boolean): Promise<void> {
|
||||||
|
|||||||
Reference in New Issue
Block a user