fix(gateway): probe /api/health instead of root URL (#394)
* fix(gateway): probe /api/health instead of root URL for health checks (#390) The server-side gateway health probe was fetching the root URL (/) which returns HTTP 400 on OpenClaw 2026.3.13 gateways. The gateway exposes a dedicated /api/health endpoint that returns 200 with status info. The WebSocket ping RPC 'unknown method' issue is already handled — websocket.ts detects the INVALID_REQUEST and falls back to passive heartbeat mode. The actual bug was this HTTP probe hitting the wrong endpoint. Fixes #390 * fix(gateway): ensure gateways table exists before health probe The gateways table is created lazily by the gateways API (ensureTable). The health route was querying it directly without CREATE IF NOT EXISTS, causing SqliteError: no such table: gateways in fresh databases (E2E tests, Docker first-boot). Add ensureGatewaysTable() inline to mirror the pattern in route.ts. * fix: update health-utils test to match /api/health probe path The test file has its own copy of buildGatewayProbeUrl — update it to append /api/health instead of / to match the route.ts change. --------- Co-authored-by: Nyk <0xnykcd@googlemail.com>
This commit is contained in:
parent
0acf7daf32
commit
301ee9cdd8
|
|
@ -80,7 +80,7 @@ function buildGatewayProbeUrl(host: string, port: number): string | null {
|
||||||
if (!parsed.port && Number.isFinite(port) && port > 0) {
|
if (!parsed.port && Number.isFinite(port) && port > 0) {
|
||||||
parsed.port = String(port)
|
parsed.port = String(port)
|
||||||
}
|
}
|
||||||
if (!parsed.pathname) parsed.pathname = '/'
|
parsed.pathname = parsed.pathname.replace(/\/+$/, '') + '/api/health'
|
||||||
return parsed.toString()
|
return parsed.toString()
|
||||||
} catch {
|
} catch {
|
||||||
return null
|
return null
|
||||||
|
|
@ -88,7 +88,7 @@ function buildGatewayProbeUrl(host: string, port: number): string | null {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Number.isFinite(port) || port <= 0) return null
|
if (!Number.isFinite(port) || port <= 0) return null
|
||||||
return `http://${rawHost}:${port}/`
|
return `http://${rawHost}:${port}/api/health`
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseGatewayVersion(headers: Record<string, string | null>): string | null {
|
function parseGatewayVersion(headers: Record<string, string | null>): string | null {
|
||||||
|
|
@ -180,7 +180,7 @@ describe('isBlockedUrl', () => {
|
||||||
|
|
||||||
describe('buildGatewayProbeUrl', () => {
|
describe('buildGatewayProbeUrl', () => {
|
||||||
it('builds URL from bare host + port', () => {
|
it('builds URL from bare host + port', () => {
|
||||||
expect(buildGatewayProbeUrl('example.com', 8080)).toBe('http://example.com:8080/')
|
expect(buildGatewayProbeUrl('example.com', 8080)).toBe('http://example.com:8080/api/health')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('preserves https:// protocol', () => {
|
it('preserves https:// protocol', () => {
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ function buildGatewayProbeUrl(host: string, port: number): string | null {
|
||||||
if (!parsed.port && Number.isFinite(port) && port > 0) {
|
if (!parsed.port && Number.isFinite(port) && port > 0) {
|
||||||
parsed.port = String(port)
|
parsed.port = String(port)
|
||||||
}
|
}
|
||||||
if (!parsed.pathname) parsed.pathname = '/'
|
parsed.pathname = parsed.pathname.replace(/\/+$/, '') + '/api/health'
|
||||||
return parsed.toString()
|
return parsed.toString()
|
||||||
} catch {
|
} catch {
|
||||||
return null
|
return null
|
||||||
|
|
@ -152,7 +152,7 @@ function buildGatewayProbeUrl(host: string, port: number): string | null {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Number.isFinite(port) || port <= 0) return null
|
if (!Number.isFinite(port) || port <= 0) return null
|
||||||
return `http://${rawHost}:${port}/`
|
return `http://${rawHost}:${port}/api/health`
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue