MCPcopy Create free account
hub / github.com/Kilo-Org/cloud / proxyThroughTarget

Function proxyThroughTarget

services/kiloclaw/src/index.ts:180–312  ·  view source on GitHub ↗

* Forward an HTTP or WebSocket request through to a provider-routed target. * * Shared by all four catch-all proxy branches (`/i/:instanceId/*`, host-based, * cookie-routed, and default personal). `logTag` is prepended to console logs * so failing requests can be traced back to their originating

(opts: {
  request: Request;
  targetUrl: string;
  forwardHeaders: Headers;
  logTag: string;
  unreachableHint?: string;
  startingUpHint?: string;
})

Source from the content-addressed store, hash-verified

178 targetUrl: string;
179 forwardHeaders: Headers;
180 logTag: string;
181 unreachableHint?: string;
182 startingUpHint?: string;
183}): Promise<Response> {
184 const { request, targetUrl, forwardHeaders, logTag, unreachableHint, startingUpHint } = opts;
185 const isWebSocketRequest = request.headers.get('Upgrade')?.toLowerCase() === 'websocket';
186
187 const unreachableBody: Record<string, string> = { error: 'Instance not reachable' };
188 if (unreachableHint) unreachableBody.hint = unreachableHint;
189 const startingUpBody: Record<string, string> = { error: 'Instance is starting up' };
190 if (startingUpHint) startingUpBody.hint = startingUpHint;
191
192 if (isWebSocketRequest) {
193 let containerResponse: Response;
194 try {
195 containerResponse = await fetch(targetUrl, { headers: forwardHeaders });
196 } catch (err) {
197 console.error(`${logTag} WS fetch failed:`, err);
198 return Response.json(unreachableBody, {
199 status: 503,
200 headers: { 'Retry-After': '5' },
201 });
202 }
203
204 if (containerResponse.status === 502) {
205 return Response.json(startingUpBody, {
206 status: 503,
207 headers: { 'Retry-After': '5' },
208 });
209 }
210
211 const containerWs = containerResponse.webSocket;
212 if (!containerWs) {
213 // Upstream returned a non-upgrade response to a WebSocket request.
214 // Normalize to 502 JSON rather than leaking the raw upstream body —
215 // this path is only hit when the container is in a bad state
216 // (gateway crash, proxy misconfig) and the raw response may contain
217 // provider/controller error details we don't want to surface to
218 // the Control UI.
219 console.warn(`${logTag} upstream did not upgrade (status ${containerResponse.status})`);
220 return Response.json({ error: 'WebSocket upgrade failed' }, { status: 502 });
221 }
222
223 const [clientWs, serverWs] = Object.values(new WebSocketPair());
224 serverWs.accept();
225 containerWs.accept();
226
227 let droppedToContainer = 0;
228 let droppedToClient = 0;
229
230 serverWs.addEventListener('message', event => {
231 if (containerWs.readyState === WebSocket.OPEN) {
232 containerWs.send(event.data as string | ArrayBuffer);
233 } else {
234 droppedToContainer++;
235 if (droppedToContainer === 1) {
236 console.warn(
237 `${logTag} First dropped client->container message (readyState:`,

Callers 2

index.tsFile · 0.85
handleHostBasedRouteFunction · 0.85

Calls 15

startingUpPageFunction · 0.90
transformWsMessageFunction · 0.85
logDropSummaryFunction · 0.85
safeCloseFunction · 0.85
sanitizeCloseReasonFunction · 0.85
getMethod · 0.65
errorMethod · 0.65
jsonMethod · 0.65
warnMethod · 0.65
valuesMethod · 0.65
acceptMethod · 0.65
sendMethod · 0.65

Tested by

no test coverage detected