@phren/cli
Version:
Knowledge layer for AI agents - CLI, MCP server, and data layer
38 lines (37 loc) • 2.1 kB
JavaScript
import { request } from "node:http";
import { BridgeError, object, socketPath } from "./protocol.js";
export async function hookRequest(route, data, options = { socketPath: socketPath() }, timeout = 75_000) {
return new Promise((resolve, reject) => {
const payload = data === undefined ? undefined : JSON.stringify(data);
const method = options.method ?? (payload === undefined ? "GET" : "POST");
const req = request({ ...options, path: route, method,
headers: { Host: "phren.local", Connection: "close", ...(payload ? { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(payload) } : {}) } }, response => {
const chunks = [];
let size = 0;
response.on("data", chunk => {
size += chunk.length;
if (size > 1_048_576)
req.destroy(new BridgeError(502, "Hook response is too large."));
else
chunks.push(Buffer.from(chunk));
});
response.on("error", reject);
response.on("end", () => {
try {
const value = object(JSON.parse(Buffer.concat(chunks).toString()));
// A remote Hook's `code` (why its Herdr is offline, say) travels on with its text.
if (response.statusCode !== 200)
throw new BridgeError(response.statusCode ?? 502, typeof value.error === "string" ? value.error.slice(0, 500) : "Hook rejected the request.", typeof value.code === "string" && /^[a-z][a-z0-9-]{0,39}$/.test(value.code) ? { code: value.code } : undefined);
resolve(value);
}
catch (error) {
reject(error);
}
});
});
const timer = setTimeout(() => req.destroy(new BridgeError(504, "Hook did not confirm the request. Do not retry a dispatch automatically.")), timeout);
req.on("close", () => clearTimeout(timer));
req.on("error", reject);
req.end(payload);
});
}