From 955eb113bb1c72f69068d1dbc95c4b442637fde1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 02:51:17 +0000 Subject: [PATCH 1/3] Initial plan From 0e0ef0a1054a132680c6017332c2095aaa2539ec Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 03:15:23 +0000 Subject: [PATCH 2/3] Refactor createProviderServer into focused handlers --- containers/api-proxy/server.js | 126 ++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 41 deletions(-) diff --git a/containers/api-proxy/server.js b/containers/api-proxy/server.js index c662c35d6..45cfa99c8 100644 --- a/containers/api-proxy/server.js +++ b/containers/api-proxy/server.js @@ -436,56 +436,61 @@ async function fetchStartupModels(adapters = []) { * behaviour (auth, URL transforms, body transforms) is delegated to the adapter. * * @param {import('./providers').ProviderAdapter} adapter - * @returns {http.Server} + * @returns {(req: http.IncomingMessage, res: http.ServerResponse) => void} */ -function createProviderServer(adapter) { - const server = http.createServer((req, res) => { - // ── Management endpoints (designated port only) ────────────────────────── - if (adapter.isManagementPort && handleManagementEndpoint(req, res)) return; - - // ── Provider-local health endpoint ─────────────────────────────────────── - if (req.url === '/health' && req.method === 'GET') { - if (adapter.isEnabled()) { - res.writeHead(200, { 'Content-Type': 'application/json' }); - res.end(JSON.stringify({ status: 'healthy', service: `awf-api-proxy-${adapter.name}` })); - } else if (adapter.getUnconfiguredHealthResponse) { - const { statusCode, body } = adapter.getUnconfiguredHealthResponse(); - res.writeHead(statusCode, { 'Content-Type': 'application/json' }); - res.end(JSON.stringify(body)); - } else { - res.writeHead(503, { 'Content-Type': 'application/json' }); - res.end(JSON.stringify({ status: 'not_configured', service: `awf-api-proxy-${adapter.name}` })); - } - return; - } - - // ── Provider-local reflect endpoint ────────────────────────────────────── - if (req.url === '/reflect' && req.method === 'GET') { +function createHealthCheckHandler(adapter) { + return (req, res) => { + if (adapter.isEnabled()) { res.writeHead(200, { 'Content-Type': 'application/json' }); - res.end(JSON.stringify(reflectEndpoints())); - return; + res.end(JSON.stringify({ status: 'healthy', service: `awf-api-proxy-${adapter.name}` })); + } else if (adapter.getUnconfiguredHealthResponse) { + const { statusCode, body } = adapter.getUnconfiguredHealthResponse(); + res.writeHead(statusCode, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify(body)); + } else { + res.writeHead(503, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ status: 'not_configured', service: `awf-api-proxy-${adapter.name}` })); } + }; +} - // ── Disabled adapter: return provider-specific error ───────────────────── - if (!adapter.isEnabled()) { - const response = adapter.getUnconfiguredResponse - ? adapter.getUnconfiguredResponse() - : { statusCode: 503, body: { error: `${adapter.name} proxy not configured` } }; - res.writeHead(response.statusCode, { 'Content-Type': 'application/json' }); - res.end(JSON.stringify(response.body)); - return; - } +/** + * @returns {(req: http.IncomingMessage, res: http.ServerResponse) => void} + */ +function createReflectHandler() { + return (_req, res) => { + res.writeHead(200, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify(reflectEndpoints())); + }; +} + +/** + * @param {import('./providers').ProviderAdapter} adapter + * @returns {(req: http.IncomingMessage, res: http.ServerResponse) => void} + */ +function createDisabledProviderHandler(adapter) { + return (_req, res) => { + const response = adapter.getUnconfiguredResponse + ? adapter.getUnconfiguredResponse() + : { statusCode: 503, body: { error: `${adapter.name} proxy not configured` } }; + res.writeHead(response.statusCode, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify(response.body)); + }; +} - // ── Rate limiting ───────────────────────────────────────────────────────── +/** + * @param {import('./providers').ProviderAdapter} adapter + * @returns {(req: http.IncomingMessage, res: http.ServerResponse) => void} + */ +function createProxyHandler(adapter) { + return (req, res) => { const contentLength = parseInt(req.headers['content-length'] || '0', 10); if (checkRateLimit(req, res, adapter.name, contentLength)) return; - // ── Optional URL transform ──────────────────────────────────────────────── if (adapter.transformRequestUrl) { req.url = adapter.transformRequestUrl(req.url); } - // ── Proxy ───────────────────────────────────────────────────────────────── proxyRequest( req, res, adapter.getTargetHost(req), @@ -494,10 +499,15 @@ function createProviderServer(adapter) { adapter.getBasePath(req), adapter.getBodyTransform() ); - }); + }; +} - // ── WebSocket upgrade ───────────────────────────────────────────────────── - server.on('upgrade', (req, socket, head) => { +/** + * @param {import('./providers').ProviderAdapter} adapter + * @returns {(req: http.IncomingMessage, socket: import('net').Socket, head: Buffer) => void} + */ +function createWebSocketUpgradeHandler(adapter) { + return (req, socket, head) => { if (!adapter.isEnabled()) { socket.write('HTTP/1.1 503 Service Unavailable\r\nConnection: close\r\n\r\n'); socket.destroy(); @@ -515,8 +525,42 @@ function createProviderServer(adapter) { adapter.name, adapter.getBasePath(req) ); + }; +} + +/** + * @param {import('./providers').ProviderAdapter} adapter + * @returns {http.Server} + */ +function createProviderServer(adapter) { + const handleHealthCheck = createHealthCheckHandler(adapter); + const handleReflect = createReflectHandler(); + const handleDisabledProvider = createDisabledProviderHandler(adapter); + const handleProxy = createProxyHandler(adapter); + + const server = http.createServer((req, res) => { + if (adapter.isManagementPort && handleManagementEndpoint(req, res)) return; + + if (req.url === '/health' && req.method === 'GET') { + handleHealthCheck(req, res); + return; + } + + if (req.url === '/reflect' && req.method === 'GET') { + handleReflect(req, res); + return; + } + + if (!adapter.isEnabled()) { + handleDisabledProvider(req, res); + return; + } + + handleProxy(req, res); }); + server.on('upgrade', createWebSocketUpgradeHandler(adapter)); + return server; } From 20b0d3e69a3dab51a274bfcb7e15f42529d45006 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 03:41:50 +0000 Subject: [PATCH 3/3] Fix mismatched JSDoc after handler extraction --- containers/api-proxy/server.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/containers/api-proxy/server.js b/containers/api-proxy/server.js index 45cfa99c8..8215bde89 100644 --- a/containers/api-proxy/server.js +++ b/containers/api-proxy/server.js @@ -430,10 +430,7 @@ async function fetchStartupModels(adapters = []) { // ── Generic provider server factory ────────────────────────────────────────── /** - * Create an HTTP server for a provider adapter. - * - * The factory is completely agnostic of provider details — all provider-specific - * behaviour (auth, URL transforms, body transforms) is delegated to the adapter. + * Create a health-check request handler for a provider adapter. * * @param {import('./providers').ProviderAdapter} adapter * @returns {(req: http.IncomingMessage, res: http.ServerResponse) => void} @@ -529,6 +526,11 @@ function createWebSocketUpgradeHandler(adapter) { } /** + * Create an HTTP server for a provider adapter. + * + * The factory is completely agnostic of provider details — all provider-specific + * behaviour (auth, URL transforms, body transforms) is delegated to the adapter. + * * @param {import('./providers').ProviderAdapter} adapter * @returns {http.Server} */