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;" />

82 lines (80 loc) 2.88 kB
import "reflect-metadata"; import { createCopilotNodeHandler } from "./node-fetch-handler.mjs"; import { logger } from "@copilotkit/shared"; import { sendResponse } from "@remix-run/node-fetch-server"; //#region src/v2/runtime/endpoints/express-fetch-bridge.ts const METHODS_WITHOUT_BODY = new Set([ "GET", "HEAD", "OPTIONS" ]); /** * Creates a Node HTTP handler from a fetch handler, with Express body-parser * compatibility. Use this instead of `createNodeFetchHandler` in Express adapters. * * When the body stream hasn't been consumed, delegates to the generic * `createCopilotNodeHandler`. Only intercepts when Express middleware has * pre-parsed the body. */ function createExpressNodeHandler(handler) { const nodeHandler = createCopilotNodeHandler(handler); return async (req, res) => { const method = (req.method ?? "GET").toUpperCase(); if (METHODS_WITHOUT_BODY.has(method) || !hasPreParsedBody(req)) return nodeHandler(req, res); try { await sendResponse(res, await handler(buildPreParsedRequest(req, res))); } catch (err) { logger.error({ err }, "Error in Express fetch bridge (pre-parsed path)"); if (!res.headersSent) { res.statusCode = 500; res.end("Internal Server Error"); } } }; } /** * Build a Fetch Request from a Node IncomingMessage whose body stream has * already been consumed by an Express body parser. */ function buildPreParsedRequest(req, res) { const expressReq = req; const method = (req.method ?? "GET").toUpperCase(); const url = `${req.protocol || "http"}://${req.headers.host ?? "localhost"}${req.originalUrl ?? req.url ?? ""}`; const headers = new Headers(); for (const [key, value] of Object.entries(req.headers)) { if (value === void 0) continue; if (Array.isArray(value)) for (const v of value) headers.append(key, v); else headers.set(key, value); } const controller = new AbortController(); res.on("close", () => { if (!res.writableFinished) controller.abort(); }); const init = { method, headers, signal: controller.signal }; const { body, contentType } = synthesizeBody(expressReq.body); if (contentType) headers.set("content-type", contentType); headers.delete("content-length"); if (body !== void 0) init.body = body; return new Request(url, init); } function hasPreParsedBody(req) { if (req.body === void 0 || req.body === null) return false; const state = req._readableState; return Boolean(req.readableEnded || req.complete || state?.ended || state?.endEmitted); } function synthesizeBody(body) { if (Buffer.isBuffer(body) || body instanceof Uint8Array) return { body }; if (typeof body === "string") return { body }; if (typeof body === "object" && body !== null) return { body: JSON.stringify(body), contentType: "application/json" }; return {}; } //#endregion export { createExpressNodeHandler }; //# sourceMappingURL=express-fetch-bridge.mjs.map