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:
@@ -30,31 +30,31 @@ async def client():
|
||||
|
||||
class TestBearerToken:
|
||||
async def test_missing_token_rejected(self, token_enabled, client):
|
||||
resp = await client.get("/api/calls/active")
|
||||
resp = await client.get("/api/v1/calls/active")
|
||||
assert resp.status_code == 401
|
||||
assert resp.headers["www-authenticate"] == "Bearer"
|
||||
|
||||
async def test_wrong_token_rejected(self, token_enabled, client):
|
||||
resp = await client.get(
|
||||
"/api/calls/active", headers={"Authorization": "Bearer wrong"}
|
||||
"/api/v1/calls/active", headers={"Authorization": "Bearer wrong"}
|
||||
)
|
||||
assert resp.status_code == 401
|
||||
|
||||
async def test_valid_token_reaches_handler(self, token_enabled, client):
|
||||
resp = await client.get(
|
||||
"/api/calls/active", headers={"Authorization": f"Bearer {TOKEN}"}
|
||||
"/api/v1/calls/active", headers={"Authorization": f"Bearer {TOKEN}"}
|
||||
)
|
||||
# No lifespan ran, so the handler itself 503s — auth was accepted
|
||||
assert resp.status_code == 503
|
||||
|
||||
async def test_empty_token_disables_auth(self, monkeypatch, client):
|
||||
monkeypatch.setattr(get_settings(), "api_token", SecretStr(""))
|
||||
resp = await client.get("/api/calls/active")
|
||||
resp = await client.get("/api/v1/calls/active")
|
||||
assert resp.status_code == 503
|
||||
|
||||
async def test_all_api_routers_protected(self, token_enabled, client):
|
||||
for path in ("/api/calls/active", "/api/call-flows/", "/api/devices/",
|
||||
"/api/routing/rules", "/api/calls/history"):
|
||||
for path in ("/api/v1/calls/active", "/api/v1/call-flows/", "/api/v1/devices/",
|
||||
"/api/v1/routing/rules", "/api/v1/calls/history"):
|
||||
resp = await client.get(path)
|
||||
assert resp.status_code == 401, path
|
||||
|
||||
@@ -76,12 +76,12 @@ class TestRouteOrder:
|
||||
return None
|
||||
|
||||
def test_history_not_shadowed_by_call_id(self):
|
||||
route = self._resolve("/api/calls/history")
|
||||
route = self._resolve("/api/v1/calls/history")
|
||||
assert route is not None
|
||||
assert route.endpoint.__name__ == "list_history"
|
||||
|
||||
def test_call_id_still_matches(self):
|
||||
route = self._resolve("/api/calls/call_abc123")
|
||||
route = self._resolve("/api/v1/calls/call_abc123")
|
||||
assert route is not None
|
||||
assert route.endpoint.__name__ == "get_call"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user