claw / proxy.js
y4shg's picture
Update proxy.js
da76e7a verified
#!/usr/bin/env node
const http = require("http");
const https = require("https");
const { URL } = require("url");
const PORT = 8123;
// βœ… ENV CONFIG
const API_BASE = process.env.API_BASE || "";
const API_KEY = process.env.API_KEY || "";
const PROXY_KEY = process.env.PROXY_KEY || "";
if (!PROXY_KEY) {
console.error("[FATAL] PROXY_KEY is required");
process.exit(1);
}
const baseUrl = new URL(API_BASE);
// πŸ”€ Model alias map: client-facing name β†’ upstream name
const MODEL_ALIASES = {
"gpt-5.3-codex": "cx/gpt-5.3-codex",
};
function getUpstreamHeaders(contentLength) {
const headers = { "Content-Type": "application/json" };
if (API_KEY) headers["Authorization"] = `Bearer ${API_KEY}`;
if (contentLength !== undefined) headers["Content-Length"] = contentLength;
return headers;
}
function isAuthorized(req) {
const auth = req.headers["authorization"] || "";
return auth === `Bearer ${PROXY_KEY}`;
}
function rewriteModel(body) {
try {
const parsed = JSON.parse(body);
if (parsed.model && MODEL_ALIASES[parsed.model]) {
const original = parsed.model;
parsed.model = MODEL_ALIASES[parsed.model];
console.log(`[MODEL] Rewritten: "${original}" β†’ "${parsed.model}"`);
return JSON.stringify(parsed);
}
} catch (e) {
console.warn("[WARN] Could not parse body for model rewrite:", e.message);
}
return body;
}
const server = http.createServer((req, res) => {
// βœ… Health check (no auth)
if (req.method === "GET" && req.url === "/health") {
res.writeHead(200, { "Content-Type": "text/plain" });
return res.end("OK");
}
// πŸ” Enforce auth on all other routes
if (!isAuthorized(req)) {
console.log("[DENY] Unauthorized request");
res.writeHead(401, { "Content-Type": "text/plain" });
return res.end("Unauthorized");
}
if (req.method === "GET" && req.url === "/") {
res.writeHead(200, { "Content-Type": "text/plain" });
return res.end("Secure proxy running.\n");
}
console.log("----- Incoming Request -----");
console.log(`${req.method} ${req.url}`);
let chunks = [];
req.on("data", chunk => chunks.push(chunk));
req.on("end", () => {
const raw = Buffer.concat(chunks).toString();
const rewritten = rewriteModel(raw);
const bodyBuffer = Buffer.from(rewritten);
console.log("Body (forwarded):", rewritten);
console.log("----------------------------");
const options = {
protocol: baseUrl.protocol,
hostname: baseUrl.hostname,
port: baseUrl.port || (baseUrl.protocol === "https:" ? 443 : 80),
path: req.url,
method: req.method,
headers: getUpstreamHeaders(bodyBuffer.byteLength),
};
const client = baseUrl.protocol === "https:" ? https : http;
const proxyReq = client.request(options, (proxyRes) => {
// βœ… Pipe directly β€” preserves SSE streaming for stream: true responses
res.writeHead(proxyRes.statusCode, proxyRes.headers);
proxyRes.pipe(res);
});
proxyReq.on("error", (err) => {
console.error("[ERROR] Proxy request failed:", err.message);
if (!res.headersSent) {
res.writeHead(500);
res.end("Proxy error");
}
});
if (bodyBuffer.byteLength > 0) {
proxyReq.write(bodyBuffer);
}
proxyReq.end();
});
});
server.listen(PORT, () => {
console.log(`[INFO] Proxy running on http://localhost:${PORT}`);
console.log(`[INFO] Forwarding to: ${API_BASE}`);
});