Serve dashboard at /, version the REST API under /api/v1

The SvelteKit build was always made for the root (no base path); it
now mounts at / — registered last so /api/v1, /ws, /health, and /mcp
match first — and the JSON root endpoint is gone (its info lives in
/health and gateway_status). REST routers move from /api/* to
/api/v1/*; /ws and /health stay put; /mcp/ unchanged. Dashboard API
client, tests, README, and docs updated; dashboard rebuilt (build/ is
gitignored).

Verified live: / serves the UI, /api/v1 answers 200/401, the old
/api paths 404, MCP still lists 15 tools.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 14:57:45 -04:00
parent a8f06462e6
commit dff21f7d5c
9 changed files with 96 additions and 114 deletions

View File

@@ -24,15 +24,15 @@ export async function fetchHealth(): Promise<HealthStatus> {
}
export async function fetchActiveCalls(): Promise<CallSummary[]> {
return get<CallSummary[]>('/api/calls/active');
return get<CallSummary[]>('/api/v1/calls/active');
}
export async function fetchDevices(): Promise<DeviceStatus[]> {
return get<DeviceStatus[]>('/api/devices');
return get<DeviceStatus[]>('/api/v1/devices');
}
export async function hangupCall(callId: string): Promise<void> {
const res = await fetch(`/api/calls/${callId}/hangup`, { method: 'POST' });
const res = await fetch(`/api/v1/calls/${callId}/hangup`, { method: 'POST' });
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
}
@@ -41,27 +41,27 @@ export async function fetchCallHistory(
offset = 0,
): Promise<CallHistoryRow[]> {
const params = new URLSearchParams({ limit: String(limit), offset: String(offset) });
return get<CallHistoryRow[]>(`/api/calls/history?${params}`);
return get<CallHistoryRow[]>(`/api/v1/calls/history?${params}`);
}
export async function fetchCallRecord(callId: string): Promise<CallHistoryRow> {
return get<CallHistoryRow>(`/api/calls/${callId}/record`);
return get<CallHistoryRow>(`/api/v1/calls/${callId}/record`);
}
export async function fetchTranscript(callId: string): Promise<TranscriptRow[]> {
return get<TranscriptRow[]>(`/api/calls/${callId}/transcript`);
return get<TranscriptRow[]>(`/api/v1/calls/${callId}/transcript`);
}
export function recordingUrl(callId: string): string {
return `/api/calls/${callId}/recording`;
return `/api/v1/calls/${callId}/recording`;
}
export async function fetchRoutingRules(): Promise<RoutingRule[]> {
return get<RoutingRule[]>('/api/routing/rules');
return get<RoutingRule[]>('/api/v1/routing/rules');
}
export async function createRoutingRule(rule: Partial<RoutingRule>): Promise<RoutingRule> {
const res = await fetch('/api/routing/rules', {
const res = await fetch('/api/v1/routing/rules', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(rule),
@@ -74,7 +74,7 @@ export async function updateRoutingRule(
ruleId: string,
patch: Partial<RoutingRule>,
): Promise<RoutingRule> {
const res = await fetch(`/api/routing/rules/${ruleId}`, {
const res = await fetch(`/api/v1/routing/rules/${ruleId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(patch),
@@ -84,12 +84,12 @@ export async function updateRoutingRule(
}
export async function deleteRoutingRule(ruleId: string): Promise<void> {
const res = await fetch(`/api/routing/rules/${ruleId}`, { method: 'DELETE' });
const res = await fetch(`/api/v1/routing/rules/${ruleId}`, { method: 'DELETE' });
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
}
export async function setDeviceDnd(deviceId: string, enabled: boolean): Promise<void> {
const res = await fetch(`/api/routing/devices/${deviceId}/dnd`, {
const res = await fetch(`/api/v1/routing/devices/${deviceId}/dnd`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ enabled }),