UNPKG

@copilotkit/runtime

Version:

<img src="https://github.com/user-attachments/assets/0a6b64d9-e193-4940-a3f6-60334ac34084" alt="banner" style="border-radius: 12px; border: 2px solid #d6d4fa;" />

130 lines (128 loc) • 4.85 kB
require("reflect-metadata"); //#region src/v2/runtime/endpoints/single-route-helpers.ts const METHOD_NAMES = [ "agent/run", "agent/suggest", "agent/connect", "agent/stop", "info", "inspector/metadata", "inspector/learning", "transcribe", "resource/request" ]; /** * Detect a single-route JSON envelope on a request the multi-route router * could not match. * * A single-endpoint client (`useSingleEndpoint` on the frontend provider) * POSTs `{ method, params, body }` at the base path. A multi-route runtime * matches no route for that path and would otherwise answer a bare 404, giving * the developer nothing to go on. Recognising the envelope here lets the * handler name the actual cause instead. * * Deliberately conservative: it reports a method only for a POST carrying a * JSON body whose `method` is one the single-route endpoint actually accepts. * Anything else is a genuine 404 and must stay one. * * @returns The envelope's method name, or `null` if this is not an envelope. */ async function detectSingleRouteEnvelope(request) { if (request.method !== "POST") return null; if (!(request.headers.get("content-type") || "").includes("application/json")) return null; let envelope; try { envelope = await request.clone().json(); } catch { return null; } if (typeof envelope !== "object" || envelope === null) return null; const method = envelope.method; if (typeof method !== "string") return null; if (!METHOD_NAMES.includes(method)) return null; return method; } async function parseMethodCall(request) { if (!(request.headers.get("content-type") || "").includes("application/json")) throw createResponseError("Single-route endpoint expects JSON payloads", 415); let jsonEnvelope; try { jsonEnvelope = await request.clone().json(); } catch { throw createResponseError("Invalid JSON payload", 400); } return { method: validateMethod(jsonEnvelope.method), params: jsonEnvelope.params, body: jsonEnvelope.body }; } function expectString(params, key) { const value = params?.[key]; if (typeof value === "string" && value.trim().length > 0) return value; throw createResponseError(`Missing or invalid parameter '${key}'`, 400); } function createJsonRequest(base, body) { if (body === void 0 || body === null) throw createResponseError("Missing request body for JSON handler", 400); const headers = new Headers(base.headers); headers.set("content-type", "application/json"); headers.delete("content-length"); const serializedBody = serializeJsonBody(body); return new Request(base.url, { method: "POST", headers, body: serializedBody, signal: base.signal }); } /** * Rebuild a resource request carried inside the single-route JSON envelope. * * The resource path must stay relative to the mounted Runtime. This prevents * the envelope from becoming an open HTTP proxy while preserving the method, * query string, headers, and cancellation signal used by the REST handler. */ function createResourceRequest(base, path, httpMethod, body) { if (!path.startsWith("/") || path.startsWith("//")) throw createResponseError("Resource path must be Runtime-relative", 400); const resourceUrl = new URL(path, "http://copilotkit.resource"); if (resourceUrl.origin !== "http://copilotkit.resource") throw createResponseError("Resource path must be Runtime-relative", 400); const targetUrl = new URL(base.url); targetUrl.pathname = `${targetUrl.pathname.replace(/\/$/, "")}${resourceUrl.pathname}`; targetUrl.search = resourceUrl.search; const method = httpMethod.toUpperCase(); const headers = new Headers(base.headers); headers.delete("content-length"); const hasBody = method !== "GET" && method !== "HEAD" && body != null; return new Request(targetUrl, { method, headers, ...hasBody ? { body: serializeJsonBody(body) } : {}, signal: base.signal }); } function createResponseError(message, status) { return new Response(JSON.stringify({ error: "invalid_request", message }), { status, headers: { "Content-Type": "application/json" } }); } function validateMethod(method) { if (!method) throw createResponseError("Missing method field", 400); if (METHOD_NAMES.includes(method)) return method; throw createResponseError(`Unsupported method '${method}'`, 400); } function serializeJsonBody(body) { if (typeof body === "string") return body; if (body instanceof Blob || body instanceof ArrayBuffer || body instanceof Uint8Array) return body; if (body instanceof FormData || body instanceof URLSearchParams) return body; return JSON.stringify(body); } //#endregion exports.createJsonRequest = createJsonRequest; exports.createResourceRequest = createResourceRequest; exports.detectSingleRouteEnvelope = detectSingleRouteEnvelope; exports.expectString = expectString; exports.parseMethodCall = parseMethodCall; //# sourceMappingURL=single-route-helpers.cjs.map